|
88417
|
rapstomViewCoocWindowFV faVsco.|s ~#12121 on JY-20 rapstomViewCoocWindowFV faVsco.|s ~#12121 on JY-20963-fx-lHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.phoOSeiMePono© SyncFieldAction.ohoCSWnCKealCohe wWwK© WebhookSvncBatchProcelisteners> MetadataaMicrationP oedriveEh SalesforcealeeldsaOpoortunityVatchenOpportunitySyncStrategyProspectSearchStrateg.g Client.pheC DecorateActivity.php( DeletcObiectsTrait.phpoewanarinithooe nha© PayloadBuilder.phpc) Profile.php© QueryBuilder.php© QueryHandler.phpeQuerviterator.oh© QueryResults.php© Service.php© SyncBatchRedisService.pth TraitsC BaseClient ohoC BaseService.cho© CachedCrmServiceDecorato©CountryCodeResolver.ohdCrmActivityProviderinteorateCCnlACMiWMohCermcontcurationSettnosser©rmobiectctesower.onC. DefaultProsoectSearchStrateC mallteloer.ond@. FindeProsoectinterfacc.ohoC) LavouMansoe ono8. MatchDomainByEmalllntorfacC Opportun tvActvitwlatcheei lennortur tevnaCtestomiedirnenont tschd nhrHe OrnenontCostrhSrond nhnCSamviceTesconrUmacurayochict.oneeachmeimserexooecoroto.onewwwswo.neocea.cokicontoeusyixstoecr.mC) PayloadBulider.ohehar crass KesconsehondloreK4S485853899883* Exhcons JsonexceRsionenetuen arrauronstrnalinuhlabel:string,displayorder:intner ve:honeprobability:float,isclosed:bool,enented.teintlimittupdatedAt.int/nulpublic static function normalizeDealStage(array|object SdealStage): array$data = self::toArray(SdealStage):return"id' => Sdata('stageld' 2? null"Label" => Sdatal'label' 22 **"displayOrder' => (Gint) (Sdatal"displayOrder') 22 0)"active" => (bool) (Sdatal "actáve" 22 true)"probability' => (float) (Sdatal "netadata"]["probability'1 22 1.SisClosed' => (bool) (Sdataf"netadata'T["isClosed'] 22 false)'createdAt' => Sdatal'createdAt'1 22 null.updatedar a Sdaral uodated.t nuit*Chnons Hsensycentiancaetune aorolestaind. miyeyprivate statzc function toArray(arraylobnect Sdata): arrayi...;© MatchActivityCrmData.php© RecordSelector.phg© Activity.phoC) Team.phd© CiosedDealStagesService.ohg© CrmEntitvReoository.ohdAottywiaw oulteoueettodaw 1Rey=custom.logsraveto"# HS local [liminny@localhost# Conboc PhoA console (EU) x iii users (EU)# console (STAGING €1728151725173017391173%17X017K01736117871783117X01746117431174211743174411745lanitMTx: AutovGo liminny vTORDER RYTnAne M.OMaTT031 A9 A29 V3 /109 A VSELECT * FRON teans WHERE name LIKE "stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEu.enallsa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:select * fron accounts where id = 4156632:select * fron opportunities where id = 4843610:#Uodareacove#"stage_id' = 13273"accountid" = 4156632."contact_id' ="updated.at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91°:select * fron actviates order oy 1d desc;select * fron users where nane tuike "subraaSELECT * FROM opportunities HERE unid to_ bin('84a9cfad-2c87-4453-S|select * fron teans where 1d= 555%select * fron stages where tean_id = SSS;SElSiNTCONCATCU.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSElhenasa.*,onnenstil socal nccounteeJOIN users u on u.id = sa.sociable.idJOIN teans t .nc->i: on t.id = u.tean_idWHERE u.tean_id = 100 and sa.provider = 'hubspot" :select id, is_closed, is_won, stage_updated_.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 order11748select id. crn_provider id, namefron stageswhere id = 28616probabilitv, uodated at, deletesTO0У L7Inu Lo mey koukServiceTestCascadeles Orcnnworeebeionhomwwtino ooooStage: TPe orPortate1, %, 191),+0.The probability logic was identical in Nov 2025. Now let me check normalizeDealStage at that timegit show 5tdzzerdsb:app/Services/crm/Hubspot/ResponscNormalize-php | grep -A 20 "normalizeoea (Stage)public static function normalizeDealStage(array|object SdealStage): arrayScata = selt::toArray SocalStaoc):Labe Saataltstagetell, 27ull,• (int) (Sdata["display0rder'] 77 0)Also identical. Now let me check the getDea lsPipeLinesEndpoint - this is what the Nov 2025 bulk import used to fetch pipeline data. Was there adutetent endpointoend usoddnsdumet• gitap0/ erviees/e =7H665pot/50/Sece-phs/2/Hu/spot/Segyice-pheg oeais p0l nesEnppotnt sho7odey inuhesdapp/Services/Crm/Hubspot/Service.pho head -2Panaunroe eeMe mnt Callaetarch• git log -oneline -before«*2025-11-19" - app/Services/Crn/Hubspot/Service-php | head -3sded sore logging for Hubspot when.or Event by puphandle proper not found exceptions0 git show Sfd720fdSb:app/Services/Crm/Hubspot/Service-php | grep -82 -AS "getDealsPipelinesEndpoint"Ask anything (XOL)Run x+ (Skip• ONtwodtur TatmeFhechiest4 spad...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88417
|
|
88416
|
HomeDMsActivityFilesLater..•More+Slack> 0(ah]Fi HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:02:138 10Untitled +...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88416
|
|
88415
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:02:118 10Untitled +...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88415
|
|
88414
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
=rapstomViewCoocWindowFV faVsco.|s ~#12121 on JY-20963-fx-l© Service Test.phpMatchhet witermonts che© HubspotClientinterface.phMmacuryochyict.oneeachmeimserexooecoroto.one© RecordSelector.phg© Activity.phoC) Team.phdnuosooktonerwenbger.or© PayloadBuilder.phpoKimol Cimosewhoo" ResponseNormalize.phowwswo..noocea.cokecontoensyicstocc.mC) PayloadBulider.oho© CiosedDealStagesService.ohg© CrmEntitvReoository.ohdoSeimerone© SyncFieldAction.ohoCSWnCKealCohe wWwK© WebhookSvncBatchProceUisteners> MetadataaMicrationP oedriveEn SalesforceafeldsaOpoortunityVatchenOpportunitySyncStrategyProspectSearchStrateg.Sameatititeg Client.pheC DecorateActivity.php( DeletcObiectsTrait.phpoewanarinithooe nha© PayloadBuilder.phpc) Profile.php© QueryBuilder.php© QueryHandler.phpeQuerviterator.oh© QueryResults.php© Service.php© SyncBatchRedisService.pth TraitsC BaseClient oho© BaseService.cho© CachedCrmServiceDecorato©CountryCodeResolver.ohdCrmActivityProviderinteorateSINSUSSASG0EASESSSSSSеCCnlACMiWMohCermcontcurationSettnosser©rmobiectctesower.onC. DefaultProsoectSearchStrateC mallteloer.ond@. FindeProsoectinterfacc.ohoC) LavouMansoe ono8. MatchDomainByEmalllntorfacC @pportun vActvitwWatchore 6Opportun tySyneStratccvinteeennortur weundCtstomodernenont tschd nhrHe OrnenontCostrhSrond nhnehar crass Kesconsehondlorepublic static function normalizePineline(arraylobiect Spipeline): arrav'active' => (bool) (Sdata('active'] ?? true),'displavOrder' => Gint) (Sdataf 'displavûrder'1 22 0)'createdAt' => Sdatal 'createdAt'1 22 null.updatedar a> Soatal uodated.t nuitu'default' => (bool) (Sdata['default'] ?? false),'staces => Sdaralstages"y* Noroaze a Hubsoor dea stage dbdect on enneu iinto e constistent shame.* EthrowsJsonExcept.ionEcetucn arraytid:stringlnull,Labelistring.displayOrder:intproodozcatyer coatAsclose0.0o0anontodateintlmntUpoareonc.onoinueouooc scaod tunceontor aorevead acerlooeceoeanaoeannayuaae seltoaulsoeandoreurnn$id' => Sdatal'stageld'1 22 nul1.'Label' => Sdatal'label'1 22 **"dfisplavOnden' => Gint) (Sdataf'disolavOnden:1 22 8)"acove" e> tood Sdatal"actye"r toue)y'probatility' => (float) (Sdata['metadata']['probabil{ty'] ?? 1)."sClosed" e> ho0b Sdatalneracsra" liselosed"o fallse t.'createdAt' => Sdata('createdAt'] ?? nulz,undatedar e Scatall' uodatedat"ee nutt# HS local [liminny@localhostA console (EU) x iii users (EU)# console (STAGING170€171617111716171% T X01746117431742117431744Tx: AutovSo liminnyTORDER RYTnAne M.OMaTT031 A9 A29 V3 /109 A VSELECT * FRON teans WHERE name LIKE "stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEu.enallsa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:select * fron accounts where id = 4156632:select * fron opportunities where id = 4843610:#Uodareacove#"stage_id' = 13273"accountid" = 4156632."contact_id' ="updated.at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91*:select * fron actviates order oy 1d desc;select * fron users where name like "xsubrax"SELECT * FROM opportunities NHERE uuid_to_bin('04a9cfad-2c87-4453-$select * fron teans where 1d = 557select * fron stages where tean_id = SSS;SElSiNTCONCATCU.Ld, CASE WHEN u.1d = t.ouner_id THEN" (owner)" ELSElhenasa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t .nc->i: on t.id = u.tean_idWHERE u.tean_id = 100 and sa.provider = 'hubspot':select id, is_closed, is_won, stage_updated_.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 orderanihM1748select id. crn_provider id, namefron stageswhere id = 28616probabilitv, uodated at, deletesTO0У L7Inu Lo moy kuuzueServiceTestCascadeles Orcnnworeebeionhomwwtino ooooStage: TPe orPortate1, %, 191),+0.The probability logic was identical in Nov 2025. Now let me check normalizeDealStage at that timegit show 5tdzzerdsb:app/Services/crm/Hubspot/ResponscNormalize-php | grep -A 20 "normalizeoea (Stage)public static function normalizeDealStage(array|object SdealStage): arrayScata = selt::toArray SocalStaoc):Labe Saataltstagetell, 27ull,• (int) (Sdata["display0rder'] 77 0)Also identical. Now let me check the getDea lsPipeLinesEndpoint - this is what the Nov 2025 bulk import used to fetch pipeline data. Was there adutetent endpointoend usoddnsdumet• gitap0/ erviees/e =7H665pot/50/Sece-phs/2/Hu/spot/Segyice-pheg oeais p0l nesEnppotnt sho7odey inuhesdapp/Services/Crm/Hubspot/Service.pho head -2Oanarunroereve wnt Callaetarca,• git log -oneline -before«*2025-11-19" - app/Services/Crn/Hubspot/Service-php | head -3sded sore logging for Hubspot whenoor Event by puphandle proper not found exceptions0 git show 5fd720fdSb:app/Services/Crm/Hubspot/Service-php | grep -82 -A5 "getDealsPipelinesEndpoint"Ask anything (XOL)"eoohRun x+ (Skip• OuwodeatotTikchirellos "asklwhiroht4 spag...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88414
|
|
88413
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:02:088 10Untitled +...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88413
|
|
88412
|
HomeDMsActivityFilesLater..•More+Slack> 0(ah]Fi HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:02:078 10Untitled +...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88412
|
|
88411
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
rapstomViewNeweNNCCoocWindowFV faVsco.s ~#12121 on JY-20963-fx-lcSamcetescon© MatchActivityCrmData.phpHubspotClientinterface.phMmacurayochyict.oneeachmeimserexooecoroto.one© RecordSelector.phgC ACovily-prC) Team.phdnuosooktonerwenoger.or© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.phowusoswosnoocea.cokicontoeuisynostoroenC) PayloadBulider.oho© CiosedDealStagesService.ohg© CrmEntitvReoository.ohdOSeiMePono© SyncFieldAction.ohoCSWnCKealCohe wWwK© WebhookSvncBatchProcelisteners> MetadataaMicrationP oedriveen SalesforceafeldsaOpoortunityVatchenOpportunitySyncStrategyProspectSearchStrateg.Sameatititeg Client.pheC DecorateActivity.php( DeleteObjectsTrait.phpoewanarinithooe nhaSISSESGGAASASSSSESS© PayloadBuilder.phpc) Profile.php© QueryBuilder.php© QueryHandler.php© Queryiterator.php© QueryResults.php© Service.php© SyncBatchRedisService.ph TraitsC BaseClient ohoC BaseService.ohd© CachedCrmServiceDecorato© CountryCodeResolver.ohoCrmActivityProviderinteorateCCnlACMiWMoh© CrmConficurationSettinasSe©rmobiectctesower.onC.DefaultProsoectSearchStrat.C mallteloer.ond@. FindeProsoectinterfacc.ohoC) LavouMansoe ono8). MatchDomainByEmalllntorfacC Opportun tvActvitwlatcheei lennortur tevnaCtestomiedirnenont tschd nhrHe OrnenontCostrhSrond nhnehar crass Kesconsehondlorepublic static function normalizePipeline(arraylobject Spipeline): array'label' => $data('label') ?? **'active' => (bool) (Sdata("active") ?? true)"displayOrder' => (int) (Sdata["display0rder'] ?? 8)'createdAt" => Sdatal'createdAt' 22 nullUocorcort sotUoorcornork"default' => (bool) (Sdata("default' 22 false)."stages" => Sdatal 'stages'] 22 01• Nornouze a Hubsoor dea stage obtect on arneu nto a consstent shaoe.ethrowswsonExceot.onreturn arrautsdastringlinutdlabel:string,wsoouorden.inonerve thooprobabilatysfloat,eninsenthonicrentedhtentlmntodeteotentlmnpublic static function normalizeDealStage(arraylobfect SdealStage): array$data = self::toArray(SdealStage):returnSid' => Sdatal'stageld'1 22 null"label' => Sdataf'label'1 22 **'displavOrder' => Gint) (Sdataf'displawirder'1 22 8)'actsive' => (bool) (Sdataf'active'1 22 true)'probability' => (float) (Sdata['netadata']['probability'] ?? 1)Sis(losed' => (boo1) (Sdataf'netadata']fSisClosed'] 22 false).'createdAt' => Sdatal 'createdAt'1 22 null.uodatedht => Sdatal uodatedtr nute* convers arrau on obsect to assocsctive anneulCtty lwew ou teoueet today lhay=custom.log= Iaravellog# HS local [liminny@localhostA console (EU) x iii users (EU)# console (STAGING170017161716171%17221172412222172€1728T11725173017391173%17X017K anihMTx: AutovSo liminnyvTORDER RYTnAne M.OMaTT031 A9 A29 V3 /109 A VSELECT * FRON teans WHERE name LIKE "stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEu.enallsa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:select * fron accounts where id = 4156632:select * fron opportunities where id = 4843610:#Uodareacove#"stage_id' = 13273"accountid" = 4156632."contact_id' ="updated.at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91*:select * fron actvales order oy 1d descaselect * fron users where nane uike subras:SELECT * FROM opportunities HERE unid to_ bin('84a9cfad-2c87-4453-S|select * fron teans where 1d = 557select * fron stages where tean_id = SSS;SElSiNTCONCATCU.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSElhenasa.*,onnenstil socal nccounteeJOIN users u on u.id = sa.sociable.idJOIN teans t .nc->i: on t.id = u.tean_idWHERE u.tean_id = 100 and sa.provider = 'hubspot":select id, is_closed, is_won, stage_updated_.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 order1748select id. crn_provider id, namefron stageswhere id = 28616probabilitv, uodated at, deletesTO0У L7Inu Lo moy kuuLuServiceTestCascadeles Orcnnworeebeionhomwwtino ooooStage: TPe orPortate1, %, 191),+0.The probability logic was identical in Nov 2025. Now let me check normalizeDealStage at that timegit show 5tdzzerdsb:app/Services/crm/Hubspot/ResponscNormalize-php | grep -A 20 "normalizeoea (Stage)public static function normalizeDealStage(array|object SdealStage): arrayScata = selt::toArray SocalStaoc):Labe Saataltstagetell, 27ull,• (int) (Sdata["display0rder'] 77 0)Also identical. Now let me check the getDea lsPipeLinesEndpoint - this is what the Nov 2025 bulk import used to fetch pipeline data. Was there adutetent endpointoend usoddnsdumet• gitap0/ erviees/e =7H665pot/50/Sece-phs/2/Hu/spot/Segyice-pheg oeais p0l nesEnppotnt sho7odey inuhesdapp/Services/Crm/Hubspot/Service.pho head -2Oanarunroereve wnt Callaetarca,• git log -oneline -beforen*2825-11-19" - app/Services/Crn/Hubspot/Service-php | head -3sded sore logging for Hubspot when.or Event by puphandle proper not found exceptions0 git show Sfd720fdSb:app/Services/Crm/Hubspot/Service-php | grep -82 -AS "getDealsPipelinesEndpoint"Ask anything (XOL)Run x+ (Skip• ONtwodtur Tatme Rcyst4 spad...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88411
|
|
88410
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:02:068 10Untitled +...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88410
|
|
88409
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
final class ResponseNormalize
{
/**
* Normalize a HubSpot pipeline object or array into a consistent shape.
*
* @throws \JsonException
*
* @return array{
* id:string|null,
* label:string,
* active:bool,
* displayOrder:int,
* createdAt:int|null,
* updatedAt:int|null,
* default:bool,
* stages:array
* }
*/
public static function normalizePipeline(array|object $pipeline): array
{
$data = self::toArray($pipeline);
return [
'id' => $data['pipelineId'] ?? null,
'label' => $data['label'] ?? '',
'active' => (bool) ($data['active'] ?? true),
'displayOrder' => (int) ($data['displayOrder'] ?? 0),
'createdAt' => $data['createdAt'] ?? null,
'updatedAt' => $data['updatedAt'] ?? null,
'default' => (bool) ($data['default'] ?? false),
'stages' => $data['stages'] ?? [],
];
}
/**
* Normalize a HubSpot deal stage object or array into a consistent shape.
*
* @throws \JsonException
*
* @return array{
* id:string|null,
* label:string,
* displayOrder:int,
* active:bool,
* probability:float,
* isClosed:bool,
* createdAt:int|null,
* updatedAt:int|null
* }
*/
public static function normalizeDealStage(array|object $dealStage): array
{
$data = self::toArray($dealStage);
return [
'id' => $data['stageId'] ?? null,
'label' => $data['label'] ?? '',
'displayOrder' => (int) ($data['displayOrder'] ?? 0),
'active' => (bool) ($data['active'] ?? true),
'probability' => (float) ($data['metadata']['probability'] ?? 1),
'isClosed' => (bool) ($data['metadata']['isClosed'] ?? false),
'createdAt' => $data['createdAt'] ?? null,
'updatedAt' => $data['updatedAt'] ?? null,
];
}
/**
* Convert array or object to associative array.
*
* @throws \JsonException
*
* @return array<string, mixed>
*/
private static function toArray(array|object $data): array
{
return json_decode(
json_encode($data, JSON_THROW_ON_ERROR),
true,
512,
JSON_THROW_ON_ERROR
);
}
}...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88409
|
|
88408
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
rapstomViewCoocWindowFV faVsco.|s ~#12121 on JY-20963-fx-lHubspotClientinterface.phnuosooktonerwenoger.or© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.phoOSeiMePono© SyncFieldAction.ohoCSWnCKealCohe wWwK© WebhookSvncBatchProcelisteners> MetadataaMicrationP oedriveEn SalesforcealeeldsaOpoortunityVatchenOpportunitySyncStrategyProspectSearchStrateg.g Client.pheC DecorateActivity.php( DeletcObiectsTrait.phpoewanarinithooe nha© PayloadBuilder.php(© Profile.php© QueryBuilder.php© QueryHandler.php© Queryiterator.php© QueryResults.php© Service.php© SyncBatchRedisService.pth TraitsC BaseClient ohoC BaseService.cho© CachedCrmServiceDecorator© CountryCodeResolver.ohoCrmActivityProviderinteorate© CrmActivitvService.ohd© CrmConficurationSettinasSe©rmobiectctesower.onC. DefaultProsoectSearchStrateC mallteloer.ond@. FindeProsoectinterfacc.ohoC) LavouMansoe ono8). MatchDomainByEmalllntorfacC Opportun tvActvitwlatcheeennortur weundCtstomodernenont tschd nhrHe OrnenontCostrhSrond nhnCSamviceTesconr© MatchActivityCrmData.phpMmacurayochyict.oneeachmeimserexooecoroto.one© RecordSelector.phgC ACovily-prC) Team.phdwusoswosnoocea.cokicontoeuisynostoroenC) PayloadBulider.oho© CiosedDealStagesService.ohg© CrmEntitvReoository.ohdCANHSSOS&GдOSAehar crass Kesconsehondlorepublic statio function normalizePipeline (arraylobject Spipeline): array"Label" => Sdatal'Label") ??"*.'active" => (bool) (Sdatal'active") ?? true)."displayOrder' => (Sint) (Sdatal'displayürder") ?? 8)"createdat' => Sdatal'createdat") ?? null,'updatedat" => Sdatal'updatedat") ?? null,"default" => (boou) (Sdatal'default") ?? false),'stages" => Sdatal'stages") ?? 0)* nornuerze a nuospoc deac stage oofect on cricy anto a consastent shude* amonsusonexceberorBnetuon arraysSidastoinalnult,OSOLCUUNeNeTCCeNeno00rooooowhtooSHLOSCORDDOEcreatedAtsint/null.uodetedhntnntpublic static function normalizeDealStage(arraylobject SdealStage): arrayScntare self::toArraulsden Staae)returnwdChntatetnnoid ouhLabel'"displayÜrder' a> int) (Sdata "displayürder') ?? 8)'active' => (bool (Sdata "active') ?? true).'probability' »> (float) (Sdata['netadata']['probability'] ?? 1),"IsClosed' a> (bool) (Sdata("netadata'"isClosed' ?? false)."createdAt' => Sdatal'createdAt' ?? null,'updatedAt' => Sdata('updatedAt'] ?? null* Convent acrau on obfect to associative acceultwttwew outteonaettodaw Ray=custom.logsraveloe# HS local [liminny@localhostA console (EU) x iii users (EU)# console (STAGING17001716171517221172412222172€1728T117251730173)173%17X017K01736117871783117X0174617421174217431744Tx: AutovSo liminnyvPOER RYTnane, M.emara031 A9 A29 V3 /109 A VSELECT * FRON teans WHERE name LIKE "stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEu.enallsa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:aeleck x tron accoun ancht o-450054select * fron opportunities where id = 4843610:#Uodareacove#"stage_id' = 13273"accountid" = 4156632."contact_id' ="activities","updated at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91°:select * fron actvales order oy 1d descaselect * fron users where nane uike subras:SELECT * FROM opportunities HERE unid to_ bin('84a9cfad-2c87-4453-S|select * fron teans where 1d= 555%select * fron stages where tean_id = SSS;SETSTMTCONCATCU.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSElhenasa.*,honnen siil coesasccounteeJOIN users u on u.id = sa.sociable.idJOIN teans t .nc->i: on t.id = u.tean_idWHERE u.tean_id = 100 and sa.provider = 'hubspot":select id, is_closed, is_won, stage_updated_.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 orderA7I4M1748select id. crn_provider id, namefron stageswhere id = 28616probabilitv, uodated at, deletesTO0У L7inu co moy kuulrosServiceTestCascadeles Orcnnworeebeionhomwwtino ooooStage: TPe orPortate1, %, 191),+0.The probability logic was identical in Nov 2025. Now let me check normalizeDealStage at that timegit show 5tdzzerdsb:app/Services/crm/Hubspot/ResponscNormalize-php | grep -A 20 "normalizeoea (Stage)public static function normalizeDealStage(array|object SdealStage): arrayScata = selt::toArray SocalStaoc):Labe Saataltstagetell, 27ull,• (int) (Sdata["display0rder'] 77 0)Also identical. Now let me check the getDea lsPipeLinesEndpoint - this is what the Nov 2025 bulk import used to fetch pipeline data. Was there adutetent endpointoend usoddnsdumet• gitap0/ erviees/e =7H665pot/50/Sece-phs/2/Hu/spot/Segyice-pheg oeais p0l nesEnppotnt sho7odey inuhesdapp/Services/Crm/Hubspot/Service.pho head -2PanadunreriMe wnt Chlaetarca• git log -oneline -beforen*2825-11-19" - app/Services/Crn/Hubspot/Service-php | head -3ioted st vertlcation - cbeck Tosk or EVent by playare a recordhandle proper not found exceptions0 git show Sfd720fdSb:app/Services/Crm/Hubspot/Service-php | grep -82 -AS "getDealsPipelinesEndpoint"Ask anything (XOL)Run x+ (Skip• OrkehThi.ht4 spad...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88408
|
|
88407
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:59®8 10Untitled +...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88407
|
|
88406
|
Project: faVsco.js, menu
rapstomViewNeweNNCCoocWin Project: faVsco.js, menu
rapstomViewNeweNNCCoocWindowFV faVsco.s ~#12121 on JY-20963-fx-l© HubspotClientinterface.phnuosooktonerwenoger.or© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.phoOSeiMePono© SyncFieldAction.ohoCSWnCKealCohe wWwK© WebhookSvncBatchProceUisteners> MetadataMiorationP oedriveen SalesforceafeldsaopoortunitVatcherOpportunitySyncStrategyProspectSearchStrateg.g Client.pheC DecorateActivity.php( DeletcObiectsTrait.phposwan ntone non© PayloadBuilder.phpc) Profile.php© QueryBuilder.php© QueryHandler.phpel Ouartterator oho© QueryResults.php© Service.php© SyncBatchRedisService.pth TraitsC BaseClient oho© BaseService.cho© CachedCrmServiceDecorato©CountryCodeResolver.ohdCrmActivityProviderinteorate© CrmActivitvService.ohd© CrmConficurationSettingsSer©rmobiectctesower.onC. DefaultProsoectSearchStrateC mallteloer.ond@. FindeProsoectinterfacc.ohoC) LavouMansoe ono8). MatchDomainByEmalllntorfacC Opportun tvActvitwlatcheeennortur weundCtstomodec) Ornenonteho nhrHe OrnenontCostrhSrond nhn© Service Test.php© MatchActivityCrmData.phpMmkeurayocryict.onyuschedummschneoecordkorone© RecordSelector.phgC ACovily-prC) Team.phdHuosooswo.noocea.cokicontoeuisyiostoco.C) PayloadBulider.oho© CiosedDealStagesService.ohg© CrmEntitvReoository.ohdKUNИSВВSСAлSAASS&кСehar crass Kesconsehondlorepublic statio function normalizePipeline (arcaylobject Spipeline): array"Label" = Soaral'tabel?"'active' => (bool) (Sdata('actáve'] 22 true).= ont Sdaral"disolavurder"? 8"createdAt' => Sdataf'createdAt'1 29 null.uodatedht"carallundaredt' nuiaedefault' (hool) (Sdataf'default'1 >> false).Stares Shatalsrades?* Normalize a HubSpot deal stage object or array into a consistent shape.* ethrows JsonExcept.ionPreturn array!idistring null,caoct.serndisplauOrder:intaceVe.o00goroodoerurroeSCCOStO.000createdAt:int/nulzupdatedAt:int/nulzoublie static function hormalizeDealStage(arraylobject SdealStage): arraySdata = self:: toarrulsdeal Stage)""a' es Sdatal'stagetd'1 2> nul1!asollavirden =sn2arasollawin.en'ohuaetve es hodndaralactwe'dy smue"probability' »> (float) (Sdata['netadata'I('probability'] 72 1),eimneert es mhoab datalisaraderlenlose." salleet'createdat" => Sdatal'createdat") ?? null,undatodAtt es Saataltundatadat: 1 29 oul1l* Convert arrau or obiect to associative arraulAottywiaw oulteoueettodaw 1Rey=custom.logsraveloe# HS local [liminny@localhostA console (EU) x iii users (EU)# console (STAGING17001716171%17221172412222172€1728T11725173017391173%17X017K011730117871738117X0174611743117421174317441748Tx: AutovGo liminny vTORDER RYTnAne M.OMaTT031 A9 A29 V3 /109 A VSELECT * FRON teans WHERE name LIKE "stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEu.enallsa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:select * fron accounts where id = 4156632:select * fron opportunities where id = 4843610:#Uodareacove#"stage_id' = 13273"accountid" = 4156632."contact_id' ="updated.at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91*:select * fron actviates order oy 1d desc;select * fron users where nane uike subras:SELECT * FROM opportunities HERE unid to_ bin('84a9cfad-2c87-4453-S|select * fron teans where 1d= 555%select * fron stages where tean_id = SSS;SElSiNTCONCATCU.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSElhenasa.*,honnen siil coesasccounteeJOIN users u on u.id = sa.sociable_idJOIN teans t .nc->i: on t.id = u.tean_idWHERE u.tean_id = 100 and sa.provider = 'hubspot":select id, is_closed, is_won, stage_updated_.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 orderselect id. crn_provider id, name,probabilitv, undated at, deletesfron stageswhere id = 28616TO0У L7inu Lo moy kuulrosServiceTestCascadeles Orcnnworeebeionhomwwtino ooooStage: TPe orPortate1, %, 191),+0.The probability logic was identical in Nov 2025. Now let me check normalizeDealStage at that timegit show 5tdzzerdsb:app/Services/crm/Hubspot/ResponscNormalize-php | grep -A 20 "normalizeoea (Stage)public static function normalizeDealStage(array|object SdealStage): arrayScata = selt::toArray SocalStaoc):Labe Saataltstagetell, 27ull,• (int) (Sdata["display0rder'] 77 0)Also identical. Now let me check the getDea lsPipeLinesEndpoint - this is what the Nov 2025 bulk import used to fetch pipeline data. Was there adutetent endpointoend usoddnsdumet• gitap0/ erviees/e =7H665pot/50/Sece-phs/2/Hu/spot/Segyice-pheg oeais p0l nesEnppotnt sho7odey inuhesdapp/Services/Crm/Hubspot/Service.pho head -2Oanarunroereve wnt Callaetarca,• git log -oneline -beforen*2825-11-19" - app/Services/Crn/Hubspot/Service-php | head -3sded sore logging for Hubspot when.or Event by puphandle proper not found exceptions0 git show Sfd720fdSb:app/Services/Crm/Hubspot/Service-php | grep -82 -AS "getDealsPipelinesEndpoint"Ask anything (XoL)Run x+ (Skip• Outwoderesme7o%ie%t4 spad...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88406
|
|
88405
|
HomeDMsActivityFilesLater..•More+Slack> 0(ah]Fi HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:548 10Untitled +...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88405
|
|
88404
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
final class ResponseNormalize
{
/**
* Normalize a HubSpot pipeline object or array into a consistent shape.
*
* @throws \JsonException
*
* @return array{
* id:string|null,
* label:string,
* active:bool,
* displayOrder:int,
* createdAt:int|null,
* updatedAt:int|null,
* default:bool,
* stages:array
* }
*/
public static function normalizePipeline(array|object $pipeline): array
{
$data = self::toArray($pipeline);
return [
'id' => $data['pipelineId'] ?? null,
'label' => $data['label'] ?? '',
'active' => (bool) ($data['active'] ?? true),
'displayOrder' => (int) ($data['displayOrder'] ?? 0),
'createdAt' => $data['createdAt'] ?? null,
'updatedAt' => $data['updatedAt'] ?? null,
'default' => (bool) ($data['default'] ?? false),
'stages' => $data['stages'] ?? [],
];
}
/**
* Normalize a HubSpot deal stage object or array into a consistent shape.
*
* @throws \JsonException
*
* @return array{
* id:string|null,
* label:string,
* displayOrder:int,
* active:bool,
* probability:float,
* isClosed:bool,
* createdAt:int|null,
* updatedAt:int|null
* }
*/
public static function normalizeDealStage(array|object $dealStage): array
{
$data = self::toArray($dealStage);
return [
'id' => $data['stageId'] ?? null,
'label' => $data['label'] ?? '',
'displayOrder' => (int) ($data['displayOrder'] ?? 0),
'active' => (bool) ($data['active'] ?? true),
'probability' => (float) ($data['metadata']['probability'] ?? 1),
'isClosed' => (bool) ($data['metadata']['isClosed'] ?? false),
'createdAt' => $data['createdAt'] ?? null,
'updatedAt' => $data['updatedAt'] ?? null,
];
}
/**
* Convert array or object to associative array.
*
* @throws \JsonException
*
* @return array<string, mixed>
*/
private static function toArray(array|object $data): array
{
return json_decode(
json_encode($data, JSON_THROW_ON_ERROR),
true,
512,
JSON_THROW_ON_ERROR
);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88404
|
|
88403
|
rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-l© rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-l© Service Test.phpHubspotClientinterface.phC) Team.phd© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoowusoswosnoocea.cokicontoeuisynostoroenC) PayloadBulider.oho© CiosedDealStagesService.ohg© CrmEntitvReoository.ohdResponseNormalize.phoCSeMCPono© SyncFieldAction.ohoCSWnCKealCohe wWwKexisiinastaad10.02.23 Vasilev24.01.25 Papazov© WebhookSvncBatchProce3862.04.10Grandnclass Service extends BaseService implements01 A7 A149 V1V33 /1 A v 170%public function inportstages (Parray_Stypes u.novw, Psteing SmissingStageNane v,nuLl): 25tage= busznessrrocess..lYre UrPUKtUNelY1706— 17081716= Sof'actsive'1sraveloe# HS local [liminny@localhostconsole (STAGINGA console (EU) x iii users (EU)listeners> MetadataaMicrationP oedriveEh SalesforcealeeldsaOpoortunityVatchenOpportunitySyncStrategyProspectSearchStrateg.sametiteGransth19.08.18 GrahamMonowa GrhM70418— 1715select * fron activities where id = 31264367= Sthis->tean->id,enh ctoimmdthsar nhetdWothS8)-1728select * fron contacts where id = 6331639:seleekx tron account anchs 0-450054= 1726select * fron opportunities where id = 4843610:i salectable= Sol'active'l#Uodare300n8-4300-4"contact_id' ="busiiness pnocessid' = ShusinessProcesse>id2% nuaulalmaeoratdett ooe8.11.1( DeletcObiectsTrait.php2.04.18Graham#"stage_id' = 13273"updated.at" = 2826-95-22 07:16:=12219.03.18 Grahamoewanarinithooe nha-1724select * fron text relavs where created at > '2926-95-91*:Stages - fetch all existing stages upfront to avoid N+1 queries© PayloadBuilder.phpes = Sthis-›config-›stages®c) Profile.phpselect * fron actvales order oy 1d desca4.05.26428-sithirashed®© QueryBuilder.phpAnsas-sahere("type', Stage::TYPE OPPORTUNITY)I1727IIl© QueryHandler.php4.05.26eQuerviterator.oh430select * fron users where nane uike subras:-sget->keyBy(*crm provider 1d')=1729© QueryResults.php4.05.26© Service.php432=1730SELECT * FROM opportunities HERE unid to_ bin('84a9cfad-2c87-4453-S|2.10.25foreach (Sp"""stages' as SdealStage)17391© SyncBatchRedisService.pt3.10.25434Ss = ResponseNornalize::normalizeDealStage(SdealStage):E1732select * fron teans where 1d= 555%select * fron stages where tean_1d = 555:h Traits2.10.25—1733SETSTMTRaseeentono4.05.26© BaseService.cho436/x* Bvac ?Stage SexistingStage */=1735CONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSEMesanSexistingStage = SexistingStages->get(Ss('id'))© CachedCrmServiceDecoratoAosos4.05.2043₴#122onnenstil socal nccountee4.05.20I Restore soft-deleted stages that are now active in HubSpotCrmActivityProviderinteorate1738JOIN users u on u.id = sa.sociable_id4.05.20446if (SexistingStage?->trashed") && Ss('active')) 4CCnlACMiWMoh= 1755CermcontcurationSettnosserSexfatinaStage-restoreo,ahittinnetneosonetts1703WHERE u.tean_id = 100 and sa.provider = 'hubspot":©rmobiectsteso wer.ono405.26=174C. DefaultProsoectSearchStrate=1742I/ Josent stage (uodates soft-deleted records without restonina then)C mallteloer.ond3sindeProscectinternce.ono445)Sstage = Sthis->config->stages()->withTrashed()->update0rCreateCl= 1143select id, is_closed, is_won, stage_updated.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 orderonorowider 1 8 SsldoC) LavouMansoe onoMatchdomsinsysmainten1. T40528C Opportun tvActvitwlatcheeweh S8= 17431746 %—1/40select id. crn-provider id, nane, probability, undated at. deletesfron stageswhere id = 28616eennortur weundCtstomodeHe OrnenontCostrhSrond nhnvhrecoroewoet relklyclone orne nusness lorocessy useerostonsnichrecoreus// Create/update record type clondSthis->confta->recondTvpes()->update0rCoeatecf=> $p['id']Sthrisosteanosdl= nb_strimwidth($s["label'].nh strimmathScht'aher".=> Stage:: TYPE_OPPORTUNITY=> Ss['display0rder'],"is selectahle" as Sef'active'l.Tx: AutovBROER PYTnane, M.emareSo liminnyv031 A9 A29 V3 /109 A VSELECT * FRON tEaNS WHERE name LIKE "Stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEMrenasisa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':TO0У L7Thu 28 May 20:01:49ServiceTestCascadeles Orcnnworeebee.ionHlmwesotino ooro+0.• git show 5fd72@fd5b:app/Services/Crm/Hubspot/Service.php | grep -A 78 "function importStages" | tail -2:1. nCm_provider_id* o Sst*10')"tean_1dS gee pneer JHEY,The probability logic was identical in Nov 2025. Now let me chock normalizebealStage at that time:• qit shơw 51d7201d5b:app/Services/Crm/Hubspot/ResponseNormalize.php | grep -A 20 *normalizeDealStage)puotie statae tunetion noreatazevedistagetarray fobgect soeatstage: arrayhtArCe eorAMNenYaoereturn!b soatal-tabelAiso idenacal. now let me check tne getdea ispipe linestnopoint - this is wnät tne nov zuzo ou x import useo lo leich o peline oata, was there aditterent endoc nt be no vend at that timet•git log -oneline →alla/Services/Cre/Hubspot/Service-php/ xargs - sh -Cglt shou /dewtontl 1 boad -eair loo -onelin-1t1-4AlteraM - aon/Services/Cmm/Hubspot/Service.oho | head -2Bestore 1oeei tod snpge, restore in recrestedAdd permissionTmportBusinessProcesses. ...... toe oll coue tut colactarcoLesentation• qit log -oneline -before="2025-11-19" -- app/Services/Crm/Hubspot/Service.php | head -350740e988 39-9625 Tix Sr verification - check Task cor Event oy olaybodAsk anything (XOL)• OKwodturlasmeXekwiirest4 spag...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88403
|
|
88402
|
HomeDMsActivityFilesLater..•More+Slack> 0(ah]Fi HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:49®8 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88402
|
|
88401
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
1
7
149
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
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\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
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\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
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_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @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
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData 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;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_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 = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'ac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88401
|
|
88400
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
rapstomEV faVsco,ls ~ProjectvViewCooc#12121 on JY-20963-fix-InWindowTO0У L7Inu Lo mey koulU ServiceTest ~© ServiceTest.phpHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.php© SyncFieidAction.phpCSWnCKealCohe wWwK© WebhookSyncBatchProce>D IntegrationAodlisteners> MetadataMigrationP oedriveSalesforcealeeldsOpportunityMatcher17.03.25 ilian16.04.25 IvanovGrahanGraham19.03.18 Graham2.04.18GrahamOpportunitySyncStrategyProspectSearchStrategysametite20.10.21 Graham© Cient.php2.10.25© DecorateActivity.php2.04.18GrahamG DeleteObjectsTrait.php16.04.25 Ivanov2.10.25©FieldDefinitions.php© PayloadBuilder.php2.10.25© Profile.php8.11.18©QueryBullder.php2.04.18oiahim©QueryHandler.php19.03.18 Graham©Queryiterator.php©QueryResults.php4.05.26© Service.php4.05.26© SyncBatchRedisService.pt4.05.26Traits4.05.26© BaseCllent.php4.05.264.05.26© Cached Crm Service Decorator2.10.252.10.2540524.05.26© CachedCrmServiceDecorator.php©MatchActivityCrmData.phpRecordSelector.php© Activity.php© Team,phpE IaravellogA HSJJocal (jiminny@localhost]# СОЛЬОС PHUA console (EU] x ( users (EU)A console (STAGING]Cascadeles Orcnnworeeoeionhomwwtino oooo+0.ResponseNormalize.phgHwwo.noocea.cokicontooensytsdorooe© PayloadBulider.phpexisiinastaad10.02.23 Vasilev24.01.25 Papazov386© CrmÊntity Repository.phpSe jiminny~• git show 51d7201d5b:app/Services/Cra/Hubspot/Service-php | grep -A 70 "function inportStages" | tail -25031 49 A29 X3 X109 A V"crn_provider_id' = $s('id*),Crmactivity ProviderintegrateCCnlACMiWMohCermcontcurationSettnosser©rmobiectsteso wer.ono© DefaultProspectSearchStrateC mallteloer.ondC) LavouMansoe onoC Opportun tvActvitwlatcheeeennortur wewn.CtestomedProspectCache.php17.03.25 ilianHe OrnenontCostrhSrond nhn4.05.26418420422427429447class Service extends BaseService inplements170601 A7 A149 X1 X33 21 A v 1707public function inportStages(Parray Styposuvoau, Potrine SpisspngStoreNone z null): 25ta99-1708mayruvoaniuoort veroorol oproseoiyioosel"crn_provider_1d => Spl'10"J170917101. Gpchisostennosidr*> nb_strinwidth(Spt'Label'], Start 0, (width: 150),=> BusinessProcess::TYPE_OPPORTUNITY,is_selectable'=> Sp['active"].1711171217131714171517161717Il A record type is really a clone of the business process, used to store which record ;US 1218// Create/update record type cloneSthis->config->recordTypes()->update0rCreateCCE171s"cra_provider _id' => Sp['id*],=17201, G"tean_id'=> Sthis->tean->id,"Is_selectable'→> nb_strimwidth($p['label'],start: 0,width: 158).→> $p['active'),'business_process_id* => $businessProcess->id 2? null,D):// Stages - fetch all existing stages upfront to avoid N+1 querieses = Sthis->config->stages()hrrashede->ahere('type', Stage: : TYPE_OPPORTUNITY)->0e10foreach (Sp['stages'] as SdealStage) (Ss = Responselornaze::nornobelen Stage Sdeal Stage)?/zx Exar ?Stege SexistingStage */SexistingStage = SpxistingStages->get($s['id'D):// Restore soft-deleted stages that are now active in HubSpot1€ (aydstinoStaoe)-strashedtà se sef'active'1) ?=1722$17241726÷17271728=172917301731E1732-17331734=1735=1736—1733- 1738=1735=1742—1742=1743=1744=17451746 v—1/40—174811!Thc AutoORDER BY t.name, u.email;SELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SELECTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-u.enail,sa.x,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce":The probability logic was identical in Nov 2025. Now let me check nornslizebealStage at that time:select * fron activities where id = 31264367:select * fron contacts where id = 6331639;select * fron accounts where id = 4156632;select * fron opportunities where id = 4843610;#Uodare300n8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-0S-22 07:16:select * fron text_relays where created_at > '2026-05-01':• git show Sfd728fdSb:app/Services/Crn/Hubspot/ResponseNormalize-php | grep -A 28 *normalizeDealStage)public static function normalizebealstagetarray lobject sdealstage): arrayAlso idenucal. Now let me check tne getdes LsPipe Lines cndpo int - this is what the Nov 2026 bux impori uscd to leich prpeline data. Was there aselect * fron actviates order oy 1d desc;select * fron users where nane uike "subrasapet tnesEndpgin, sh°2/dev/null || hesd -eSELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:lhenasa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id= sa.sociable_idJOIN teans t 1.n<->1: on t.id = u.tean.idWHERE u.tean_id = 100 and sa.provider = "hubspet":git log -oneline -diff-f{lter-M — app/Services/Crm/Hubspot/Service.php | head -20pestrr eelieted stages,restore in recreatedtestsAdd pereission Logging for HubspotTmaortBuspoessProressess- are cleaned up tron all CPMs but Salesforce.CRMs but Salesforce.6xI/ Upsert stage (updates soft-deleted records without restoring then)Sstage = Sthis->config->stages()->withTcashed() -›update0rCreate(ESone nnovidon dat es Cereaaellselect id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 5SS and stage_id = 28616 order_*select id, crn.provider.id, nane, probability, updated.at, deleter!fron stageswhere id = 28616;O git Log —oneline —before="2825-11-19" - app/Services/Crn/Hubspot/Service.php | head -3(Run s= (Skip"tean. id"=> Sthis->team->id,=> nb_strimwidth(Ss('label'], (start: e,width: 50),Ask anything (XOL)Adhet• OytwodturlatmeXekwhi..h2 4 spao...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88400
|
|
88399
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:458 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88399
|
|
88398
|
rapstomEV faVsco,ls ~ProjectvCooc#12121 on JY-2096 rapstomEV faVsco,ls ~ProjectvCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPono© SyncFieidAction.phpCSWnCKealCohe wWwK© WebhookSyncBatchProcewwswo..noocea.cokecontoensyicstocc.mexisiinastaad10.02.23 VasilevDaeosnszollisteners> MetadataMigrationP oedriveSalesforceafeldsOpportunityMatcherOpportunitySyncStrategyProspectSearchStrategysametite© Client.php© DecorateActivity.phpG DeleteObjectsTrait.php©FieldDefinitions.php© PayloadBuilder.php© Profile.php©QueryBullder.php©QueryHandler.php©Queryiterator.php©QueryResults.php© Service.php© SyncBatchRedisService.ptTraits© BaseCllent.phpCwastemoeene© CachedCrmServiceDecorator2.04.18Graham19.03.18 Graham2.04.18Grandy3.10.252.10.25CIU.LS20.10.21 Graham2lU.LS17.05.25 mlar2.10.25Ctahnath3.10.25cransmh19.03.18 Graham2.10.2520207 Graham70413Grahhm8.11182.04.18Graham1002 18CrahsmCrmactivity ProviderintegrateCCWCMWMoron4.05.264.05.264.05.26©rmobiectctesower.on© DefaultProspectSearchStrate4.05.264.05.26 IvanosC mallteloer.ond4.05.26 Ivanov3sindeProscectinteance.ond2.10.25C) LvoutMansoeono3.10.25C Opportun tvActvitwlatchee4.05.20© OpportunitySyncStrategyResProspectCache.phpHe OrnenontCostrhSrond nhn TO0У L7Inu Lo mey LoulalU ServiceTest ~© ServiceTest.php©MatchActivityCrmData.php© Activity.php© Team,phpE IaravellogA HSJJocal (jiminny@localhost]A console (STAGING]4 SF [iminny@localhost)# СОЛЬОС PHUA console (EU] x E users (EU)Cascadeles Orcnnworeeoeionhomwso1ino ooeoVo Show Sl-CD0=onNs/anuosoowserce.cho oroosh4ocondro+0.© CiosedDealStagesService.php© CrmÊntity Repository.phpclass Service extends BaseService inplements170601 47 A149 X1 X33 21 A V 1707public function importStages(Parray $types = null, Pstring SnissingStageName = null): 2Stage—1708foreach (Spipelines as Spipeline) €17091710Sstages = (1:1711I/ We create a business process to contain the pipeline, and store all stages against it.1713$p = ResponseNornalize: :normalizePipeline(Spipeline);1715// Create/update business process for this pipelinejousznessrrocess a suzsescontzc@ousanessrrocessesouodareurcreacecri provzoer 20 5 3010-1717-17183unisoseaeson=> mb_strimwidth(Sp['label'],saltor=> BusinessProcess::TYPE_OPPORTUNITY,=> Sp['active'].=1720= 1727172311724lunecorewor railyaclone onthe ous tness orocussy lustedotormnchneconeV 1726I/ Create/update record type cloneSthis->confio->necondTvoes@->undate0rCneatech=1727>> Spt'id'],=1729=17301731mheeninmidthSor"nbelen→> Spl'actáve'),busiiness anocessid' = ShussinessProcesse>d2% nuluE1732-1733=17351736Stages - fetch all existing stages upfront to avoid N+1 queriesexistingStages = Sthis->config->stages()-withTrashedO)->ahere('type', Stage:: TYPE_OPPORTUNITY)→get-›keyBy('crn_provider_id'):E1757-1738E1739=1742—1742=1743foreach (Sp['stages'] as $dealStage) ($s = ResponseNornalize: :normalizeDealStage(SdealStage);=1744=17451746 vThc AutoORDER BY t.nane, u.email;Se jiminny~031 49 A29 X3 X109 A VSELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SELECTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-u.enail,sa.x,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce":• git show Sfd728fdSb:app/Services/Crn/Hubspot/Service-php | grep -A 50 "function inportStages"public function ieportStages(zarray stypes e nutl, istring salssingStagclame = nutl): 75tageSaissingStage • null;try i use the HubSpot API client instead of the SOK crmPipelines() sethodce()->getClient ()->request('GET', Sendpoint):mmand di oreo.tat show Stozz roso:aoo/Servicos//cra/Hubspot/Service.pho areo an 78 "Tunction teoor Staoestart=5"emorouider d' n scrid"select * fron activities where id = 31264367:select * fron contacts where id = 6331639;select * fron accounts where id = 4156632;select * fron opportunities where id = 4843610;#Uodare0c0un8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-05-22 07:16:1, L: 8, 59%5.B ssl'probabatlty'1 100)select * fron text_relays where created_at > '2026-05-01':tihworobnsry loccwrklidcoatinotorowilet.mechockcrtreoensthcehthattmselect * fron actvales order oy 1d desca• qít show S187201d5b:app/Services/Crm/Hubspot/ResponseNormalize.php | grep -A 20 "norma Lizedea lStage)select * fron users where nane uike subras:public static function nornalizedealStagelarray|object sdeatstage): arraySELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-swaesetowronas aoeselect * fron teans where 1d= 555%return.!select * fron stages where tean_id = 555;SETSTMT2 o acttdiplaytroer') ®),CONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:lhenasa.*,t.ouner_id FROM social_accounts sa©at od mooelin cditoaiterl e aon/Services/Cmy/Hubsoot /Servi co,oho lhead =213T22yd0500 J7-20801 KestoreJOIN users u on u.id = sa.sociable_idrestore in recreatedJOIN teans t 1.n<->1: on t.id = u.tean.idWHERE u.tean_id = 100 and sa.provider = 'hubsRes":/кx @xac ?Stage SexistingStage */SexistingStage = SexistingStages->get(Ss['id'D);select id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 5SS and stage_id = 28616 order_*select id, crn_provider_id, nane, probability, updated_at, deleterefron stageswhere id = 28616;"Dtt ctRs but Sples ore cleaned up fron all CRMs but Solesforce1/ Restore soft-deleted stages that are now active in HubSpotif (SexistingStage?->trashed() && $s('active']) €—174811!Ask anything (XOL)• OKwodturlasmeXekwiires2 4 spac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88398
|
|
88397
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
rapstomEV faVsco,ls ~#12121 on JY-20963-fix-InProjectvCoocWindowThu 28 May 20:01:33U ServiceTest ~© ServiceTest.php© DeleteObjects Trait.php©MatchActivityCrmData.phpE custom.logE Iaravellog4 SF [iminny@localhost)CascadeHubspotClientinterface.phRecordSelector.php© Activity.php© Team,phpA HSJJocal (jiminny@localhost]# Conboc PhoA console (EU] x ( users (EU)les Orcnnworeebeeionhomwstotino ooso+0.© HubspotTokenManager.pt© PayloadBuilder.phpA console (STAGING]oKimol Cimosewhoowwswo..noocea.cokecontoensyicstocc.m© PayloadBulider.php© CiosedDealStagesService.php© CrmÊntity Repository.phpThc AutoSe jiminny~© ResponseNormalize.php1705ORDER BY t.nane, u.email;• git show Std720fdSb:app/Services/Crn/Hubspot/Service-php | grep -A 50 "function inportStages"1706031 49 A29 X3 X109 A VCSeMCPonoexistinastaadecwpubtic tunction amportstages (rarray Stypes = nutt, (string saissingstagenane = nutt): 15tage© SyncFieidAction.php10.02.23 Vasilevclass Service extends BaseService inplements01 47 A149 X1 233 21 A V 1707SELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SaissingStage = nult;CSWnCKealCohe wWwK24.01.25 Papazovpublic function inportStages(Parray Stypes = null, Pstring SnissingStageName = null): 2Stage-1708SEEiNT© WebhookSyncBatchProce1709CONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-try(// Use the HubSpot APT client instead of the SDK crapipelines() nethod391// Use the HubSpot API client instead of the SDK crmPipelines() nethod1710u.enail,onse - 5this-scltent-sgetinstance()-agetCLient ()-эrequest('GET', Sendpoint):listeners3.10.25Sendpoint = self::getDealsPipelinesEndpoint():sa.x,> Metadata13.10.25 Nikolov3931711SpipelinesResponse = Sthis->client->getInstance()-›getCLient()->request( method: 'GET", Sen 1712t.ouner_id FROM social_accounts saMigration13.10.25 NikolovSpipelines = SpipelinesResponse-›data-›results;JOIN users u on u.id = sa.sociable_idP oedrive10.09.25 flianSalesforce24.04.18 Graham395} catch (RequestException|BadRequest Sexception) (сллou pexсeaeoth1715JOIN teans t 1.nc->1: on t.id = u.tean_idoshowololo100owresr@/huosco@/servce.onoortounceloncoorsoor=WHERE u.tean_id = 187 and sa.provider = 'salesforce":afelds24.04.18 Graham*crn_provider_id' = $s('1d'),OpportunityMatcher19.03.18 GrahamOpportunitySyncStrategy-1717select * fron activities where id = 31264367:121025 NikoloProspectSearchStrategy2.04.18Graham399foreach (Spipelines as Spipeline) (-1718Sstages = [J:-1728select * fron contacts where id = 6331639;ab strimwioth(sst' Larteatatssr uabel:l: 8, 191.select * fron accounts where id = 4156632;sametite19.03.18 Grahamselect * fron opportunities where id = 4843610;© Cient.php2.04.18#Uodare0c0un8-4300-4"contact_id' = 6.© DecorateActivity.php3.10.25403$p = ResponseNornalize: :nornalizePipeline(Spipeline);#"stage_id' = 13273,"updated_at' = 2026-05-22 07:16:G DeleteObjectsTrait.php2.10.25The probablTity locic was identical in Nov 2025. Now let me check norma &izedea Stace at that timel©FieldDefinitions.php// Create/update business process for this pipelineselect * fron text_relays nhere created_at > '2026-05-01':© PayloadBuilder.php20.10.21 GrahamSbusinessProcess = Sthis->config->businessProcesses()->update0rCreateCE© Profile.php2.10.25©QueryBullder.php17.03.25 ilian407select * fron actvales order oy 1d desca408)1, ttoshowoturoortoo/terces/criuos.cou//Resoonscwor.lozze.ohoor80=7n0m0701215.000publie statie function normslizeDealStage(array lobject sdealStage): array©QueryHandler.php1604.75 Ivanov409= his-xean->1d.©Querylterator.php2.10.25=> mb_strimwidth(Sp( 'label'],Start 8rwiodt58)©QueryResults.php2.04.18Graham•> BusinessProcess: :TYPE_OPPORTUNITY,© Service.php3.10.25→> $p['active'].© SyncBatchRedisService.pt2.04.18GrahamTraits19.03.18 Graham© BaseCllent.php04418© BaseService.php2.10.2511 eretoro eate ie oeatye clone of the business proces, vsed fo stere mnich recend vn// Create/update record type clone© Cached Crm Service DecoratorSthisosconfiaesnecondTvnes(l-sundatehofceatech© CrmActivityProviderintegrateCCnlACMiWMoh1, 0©rmobiectctesower.on© DefaultProspectSearchStrateC Emal telcerond3sindeProscectinteance.ondC) LavouMansoe onoeraewdthssolahe"is_selectable'>> Sp['actáve'),"business_process_id' = $businessProcess->id ?? nulz,2.04.18Graham100218 GrabanC Opportun tvActvitwlatchee© OpportunitySyncStrategyResProspectCache.phpHe OrnenontCostrhSrond nhn426428430432D):(/ Stages - fetch all existing stages upfront to avoid N+1 queriesexistingStages = Sthis->config->stages()-withTrashedO-›ahere('type', Stage:: TYPE_OPPORTUNITY)→getO-›keyBy('crn_provider_id'):=1727=172917301731E152E1757-1738E1739=1742—1742=1743=1744=17451746 v— 1/40—174811!select * fron users where nane uike subras:SELECT * FROM opportunities HHERE wuid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTlhenasa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.n<->1: on t.id = u.tean.idWHERE u.tean_id = 100 and sa.provider = 'hubsRes":(sdatal'"displayOrder') 27 0),→(bool)" (Sdatal"active"CONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:Also identical. Now let me check the oetdes &Pioe Tines Endoo int - this is what the Noy 2025 ouimoort uerd to tetch o oeline data, Was there &different endpoint being used at that time?• g1t 109 - onellne -Bll - spp/Services/Cra/tubspot/Service-php / xargs -20) sh -c git, ahon2/dev/null | head -SCommand cin nasoselect id, is_closed, is_won, stage_updated_at, crn_provider_id, atclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 5SS and stage_id = 28616 order_*select id, crn_provider_id, nane, probability, updated_at, deleterefron stageswhere id = 28616;O git log —oneline -diff-filtersM - app/Services/Crm/Hubspot/Service-php | head -20Run st= (SkipAsk anything (XOL)Adhetforeach (Sof'stages'] as SdealStaae) (• OKwodturlasmeXekwiires2 4 space...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88397
|
|
88396
|
HomeDMsActivityFilesLater..•More+Slack> 0(ah]Fi HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:348 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88396
|
|
88395
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
final class ResponseNormalize
{
/**
* Normalize a HubSpot pipeline object or array into a consistent shape.
*
* @throws \JsonException
*
* @return array{
* id:string|null,
* label:string,
* active:bool,
* displayOrder:int,
* createdAt:int|null,
* updatedAt:int|null,
* default:bool,
* stages:array
* }
*/
public static function normalizePipeline(array|object $pipeline): array
{
$data = self::toArray($pipeline);
return [
'id' => $data['pipelineId'] ?? null,
'label' => $data['label'] ?? '',
'active' => (bool) ($data['active'] ?? true),
'displayOrder' => (int) ($data['displayOrder'] ?? 0),
'createdAt' => $data['createdAt'] ?? null,
'updatedAt' => $data['updatedAt'] ?? null,
'default' => (bool) ($data['default'] ?? false),
'stages' => $data['stages'] ?? [],
];
}
/**
* Normalize a HubSpot deal stage object or array into a consistent shape.
*
* @throws \JsonException
*
* @return array{
* id:string|null,
* label:string,
* displayOrder:int,
* active:bool,
* probability:float,
* isClosed:bool,
* createdAt:int|null,
* updatedAt:int|null
* }
*/
public static function normalizeDealStage(array|object $dealStage): array
{
$data = self::toArray($dealStage);
return [
'id' => $data['stageId'] ?? null,
'label' => $data['label'] ?? '',
'displayOrder' => (int) ($data['displayOrder'] ?? 0),
'active' => (bool) ($data['active'] ?? true),
'probability' => (float) ($data['metadata']['probability'] ?? 1),
'isClosed' => (bool) ($data['metadata']['isClosed'] ?? false),
'createdAt' => $data['createdAt'] ?? null,
'updatedAt' => $data['updatedAt'] ?? null,
];
}
/**
* Convert array or object to associative array.
*
* @throws \JsonException
*
* @return array<string, mixed>
*/
private static function toArray(array|object $data): array
{
return json_decode(
json_encode($data, JSON_THROW_ON_ERROR),
true,
512,
JSON_THROW_ON_ERROR
);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
31
9
29
3
109
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM team_features where team_id = 1;
SELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922
SELECT * FROM users WHERE team_id = 340; # 12015
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 340
and sa.provider = 'salesforce';
# and sa.provider = 'salesloft';
select * from crm_fields where crm_configuration_id = 270 and object_type = 'event';
# 125558 - Event Type - Event_Type__c
# 125552 - Event Status - Event_Status__c
SELECT * FROM sidekick_settings WHERE team_id = 340;
SELECT * FROM crm_field_values WHERE crm_field_id in (125552);
select * from activities where crm_configuration_id = 270
and type = 'conference' and crm_provider_id IS NOT NULL
and actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;
SELECT * FROM activities WHERE id = 20871677;
SELECT * FROM crm_field_data WHERE activity_id = 20871677;
select * from crm_layouts where crm_configuration_id = 270;
select * from crm_layout_entities where crm_layout_id in (886,887);
SELECT * FROM crm_configurations WHERE id = 270;
select * from playbooks where team_id = 340; # 1514
select * from groups where team_id = 340;
SELECT * FROM crm_fields WHERE id IN (125393, 125401);
select g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g
join playbooks p on g.playbook_id = p.id
join crm_fields f on p.activity_field_id = f.id
where g.team_id = 340;
SELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716
select * from crm_field_data where object_id = 20448716;
select * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008
select * from opportunities where team_id = 343;
select * from opportunities where team_id = 343 and crm_provider_id = '18099102526';
select * from opportunities where team_id = 343 and account_id = 945217482;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
select * from accounts where team_id = 343 order by name asc;
select * from stages where crm_configuration_id = 273 and type = 'opportunity';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143
SELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;
SELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';
SELECT * FROM activities WHERE id = 20717903;
select * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 353
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;
# id: 20940638, user: 12022, contact: 5305871
SELECT * FROM activity_summary_logs WHERE activity_id = 20940638;
select * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 345
and sa.provider = 'hubspot';
select * from users where team_id = 345 and id = 12022;
SELECT * FROM crm_profiles WHERE user_id = 12022;
SELECT * FROM participants WHERE activity_id = 20940638;
SELECT * FROM users u
JOIN crm_profiles cp ON u.id = cp.user_id
WHERE u.team_id = 345;
select * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871
select * from team_features where team_id = 345;
SELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197
SELECT * FROM participants WHERE activity_id = 20897406;
SELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912
SELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';
SELECT * FROM activities WHERE id = 20946641;
SELECT * FROM crm_profiles WHERE user_id = 10211;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, [EMAIL]
SELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';
select * from stages where crm_configuration_id = 97 and type = 'opportunity';
select * from opportunities where team_id = 120;
select * from crm_configurations crm join teams t on crm.id = t.crm_id
where 1=1
AND t.current_billing_plan IS NOT NULL
AND crm.auto_sync_activity = 0
and crm.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 270
and sa.provider = 'salesforce';
SELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956
SELECT * FROM crm_profiles WHERE user_id = 11446;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, [EMAIL]
select * from playbooks where team_id = 372;
select * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340
SELECT * FROM crm_field_values WHERE crm_field_id = 141340;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 372
and sa.provider = 'salesforce';
select * from crm_profiles where crm_configuration_id = 300;
SELECT * FROM crm_configurations WHERE team_id = 372;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,[EMAIL]
SELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756
select * from crm_field_data where object_id = 3207756;
SELECT * FROM crm_fields WHERE id = 111834;
select f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value
FROM crm_fields f
JOIN crm_field_data fd ON f.id = fd.crm_field_id
WHERE f.crm_configuration_id = 242
AND f.object_type = 'opportunity'
AND fd.object_id IN (3207756)
ORDER BY fd.object_id, fd.updated_at;
SELECT * FROM crm_configurations WHERE auto_connect = 1;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,[EMAIL]
select * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id
where g.team_id = 187;
select * from `groups` where team_id = 187;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 187
and sa.provider = 'salesforce';
# Destination - 98870 - Destination__c
# Stage - 79014 - StageName
# Land Arrangement - 98856 - Land_Arrangement__c
# Flight - 98848 - Flight__c
# Last activity date - 98812 - LastActivityDate
# Last modified date - 98809 - LastModifiedDate
# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c
# next call - 98864 - Next_Call__c
select * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
select * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';
select * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;
select * from activities where opportunity_id = 3538248;
SELECT * FROM crm_profiles WHERE user_id = 8150;
select * from deal_risks where opportunity_id = 3538248;
select * from teams where crm_id IS NULL;
SELECT opp.id AS opportunity_id,
u.group_id AS group_id,
MAX(
CASE
WHEN a.type IN ("sms-inbound", "sms-outbound") THEN a.created_at
ELSE a.actual_end_time
END) as last_date
FROM opportunities opp
left join activities a on a.opportunity_id = opp.id
inner join users u on opp.user_id = u.id
where opp.user_id IN (9951)
AND opp.is_closed = 0
and a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL
group by opp.id;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_profiles WHERE crm_configuration_id = 301;
SELECT * FROM contacts WHERE id = 6612363;
SELECT * FROM accounts WHERE id = 4235676;
SELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;
select * from opportunity_stages where opportunity_id = 4503759;
# SELECT * FROM opportunities WHERE id = 4569937;
select * from activities where crm_configuration_id = 301;
SELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370
SELECT * FROM participants WHERE activity_id = 26330370;
SELECT * FROM teams WHERE id = 375;
select * from playbooks where team_id = 375;
select * from stages where crm_configuration_id = 301 and type = 'opportunity';
select * from teams;
select * from contact_roles;
SELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';
select * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;
SELECT * FROM crm_field_data WHERE object_id = 3771706;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'
and crm_provider_id LIKE "%traffic_light%";
SELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);
SELECT fd.* FROM opportunities o
JOIN crm_field_data fd ON o.id = fd.object_id
WHERE o.team_id = 343
# and o.user_id IS NOT NULL
and fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)
and fd.value != ''
order by value desc
# group by o.id
;
SELECT * FROM opportunities WHERE id = 3769843;
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, [EMAIL]
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,[EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839
SELECT * FROM opportunities WHERE id = 3855992;
SELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988
SELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894
SELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';
select * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507
SELECT * FROM crm_field_data WHERE object_id = 5874411;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 379
and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793
select * from generic_ai_prompts where subject_id = 3537793;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, [EMAIL]
SELECT * FROM crm_configurations WHERE id = 97;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 97;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;
SELECT * FROM crm_fields WHERE id = 32682;
select cfd.value, o.* from opportunities o
join crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682
where team_id = 120
and cfd.value != ''
;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 120
and sa.provider = 'salesforce';
select * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';
SELECT * FROM crm_field_data WHERE object_id = 2313439;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 410;
SELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';
select * from scorecards where team_id = 410;
select * from scorecard_rules;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, [EMAIL]
select * from activities a
join opportunities o on a.opportunity_id = o.id
join users u on o.user_id = u.id
where a.crm_configuration_id = 177 and a.type LIKE '%email-out%'
# and a.actual_end_time > '2024-12-16 00:00:00'
# and o.remotely_created_at > '2024-12-01 00:00:00'
# and u.group_id = 1014
and u.id = 9021
order by a.id desc;
SELECT * FROM opportunities WHERE id in (3981384,4017346);
SELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);
select * from users where id = 9021;
select * from inboxes where user_id = 9021;
select * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';
select * from email_messages where team_id = 220
and orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'
and subject LIKE '%Personal%'
# and 'from' = '[EMAIL]'
;
select * from activities a
join opportunities o on a.opportunity_id = o.id
where a.user_id = 9021 and a.type LIKE '%email-out%'
and a.actual_end_time > '2024-12-18 00:00:00'
and o.user_id IS NOT NULL
and o.remotely_created_at > '2024-12-01 00:00:00'
order by a.id desc;
SELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;
select * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;
select * from team_settings where name IN ('useCloseDate');
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 104
and sa.provider = 'hubspot';
select * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'
select * from teams where crm_id IS NULL;
select t.name as 'team', u.name as 'owner', u.email, u.phone
from teams t
join activity_providers ap on t.id = ap.team_id
join users u on t.owner_id = u.id
where 1=1
and t.status = 'active'
and ap.is_enabled = 1
# and u.status = 1
and ap.provider = 'ms-teams';
select * from crm_configurations where provider = 'bullhorn'; # 344
SELECT * FROM teams WHERE id = 442; # 14293
select * from users where team_id = 442;
select * from social_accounts sa where sa.sociable_id = 14293;
select * from invitations where team_id = 442;
# [PASSWORD_DOTS]
SELECT * FROM users WHERE email LIKE '%[EMAIL]%'; # 14022
SELECT * FROM teams WHERE id = 429;
select * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);
select * from activities where opportunity_id in (4340436,4353519);
select * from transcription where activity_id IN (25630961,25381771);
select * from generic_ai_prompts where subject_id IN (4353519);
SELECT
a.id as activity_id,
a.opportunity_id,
a.type as activity_type,
a.language,
CONCAT(a.title, a.description) AS mail_content,
e.from AS mail_from,
e.to AS mail_to,
e.subject AS mail_subject,
e.body AS mail_body,
p.type as prompt_type,
p.status as prompt_status,
p.content AS prompt_content,
a.actual_start_time as created_at
FROM activities a
LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL
LEFT JOIN email_messages e ON a.id = e.activity_id
WHERE a.actual_start_time > '2024-01-01 00:00:00'
AND a.opportunity_id IN (4353519)
AND a.status IN ('completed', 'received', 'delivered')
AND a.deleted_at IS NULL
AND a.type NOT IN ('sms-inbound', 'sms-outbound')
ORDER BY a.opportunity_id ASC, a.id ASC;
SELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293
SELECT * FROM teams WHERE id = 442;
SELECT * FROM crm_configurations WHERE id = 344;
select * from team_features where team_id = 442;
select * from groups where team_id = 442;
select * from playbooks where team_id = 442;
select * from playbook_categories where playbook_id = 1729;
select * from crm_fields where crm_configuration_id = 344 and id = 172024;
SELECT * FROM crm_field_values WHERE crm_field_id = 172024;
select * from crm_layouts where crm_configuration_id = 344;
select * from playbook_layouts where playbook_id = 1729;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444
select s.*
# , s.sent_at, u.name, a.*
from activity_summary_logs s
inner join activities a on a.id = s.activity_id
inner join users u on u.id = a.user_id
where a.crm_configuration_id = 356
and s.sent_at > date_sub(now(), interval 60 day)
order by a.actual_end_time desc;
select * from activities a
# inner join activity_summary_logs s on s.activity_id = a.id
where a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)
# and a.crm_provider_id is not null
# and provider <> 'ringcentral'
and status = 'completed'
order by a.actual_end_time desc;
select * from teams order by id desc; # 17328, 32, 17830, [EMAIL]
SELECT * FROM users;
SELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active
SELECT * FROM teams WHERE id = 260;
select * from team_settings where team_id = 260;
select * from crm_configurations where team_id = 260;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 356;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;
select * from accounts where crm_configuration_id = 221 order by id desc; # 7000
select * from leads where crm_configuration_id = 221 order by id desc; # 0
select * from contacts where crm_configuration_id = 221 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 221 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 221;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 221 order by id desc;
select * from stages where crm_configuration_id = 221 order by id desc;
select * from accounts where crm_configuration_id = 356 order by id desc; # 7000
select * from leads where crm_configuration_id = 356 order by id desc; # 0
select * from contacts where crm_configuration_id = 356 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 356 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 356;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 356 order by id desc;
select * from stages where crm_configuration_id = 356 order by id desc;
select * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)
select * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)
select * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4
select ce.* from calendars c
join users u on c.user_id = u.id
join calendar_events ce on c.id = ce.calendar_id
where u.team_id = 260
and (ce.start_time > '2025-02-21 00:00:00')
;
# calendar events 1207
#
select * from opportunities where team_id = 260;
SELECT * FROM crm_field_data WHERE object_id = 4696496;
select * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;
select * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')
# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0
and created_at > '2024-03-01 00:00:00'
order by id desc; # 880 000, ringcentral, avaya
SELECT * FROM participants WHERE activity_id = 26371744;
# all activities 942 000 +
# conference 7385 - scheduled 984 - external 343
select * from activities where id = 26321812;
select * from participants where activity_id = 26321812;
select * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);
select * from leads where id in (720428,689175,731546,645866,621037);
select * from users where id = 13841;
select * from opportunities where user_id = 9541;
select * from stages where id = 15900;
select * from accounts where
# id IN (4160055,5053725,4965303,4896434)
id in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)
;
select * from activities where id = 26654935;
SELECT * FROM opportunities WHERE id = 4803458;
SELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;
SELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time
FROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);
SELECT DISTINCT
o.id, o.stage_id, s.name, a.title,
a.*
FROM activities a
# INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
INNER JOIN groups g ON u.group_id = g.id
INNER JOIN opportunities o ON a.opportunity_id = o.id
INNER JOIN stages s ON o.stage_id = s.id
WHERE
a.crm_configuration_id = 356
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 13841
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')
AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
)
)
AND (
# s.id = 15900
s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')
OR s.uuid IS NULL -- Include records without opportunity stage
)
ORDER BY a.actual_end_time DESC;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, [EMAIL]
SELECT * FROM users WHERE team_id = 190;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 190
and sa.provider = 'hubspot';
select * from role_user where user_id = 8474;
select * from crm_configurations where provider = 'bullhorn';
SELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;
SELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;
SELECT * FROM opportunities WHERE id = 4732493;
select * from activities where opportunity_id = 4732493;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 443; # 358, 14315, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 443;
SELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id
FROM activities AS a
JOIN stages AS s ON a.stage_id = s.id
JOIN users AS u ON u.id = a.user_id
JOIN teams AS t ON t.id = s.team_id
WHERE u.team_id <> s.team_id and t.id > 135;
SELECT
crm_configuration_id,
crm_provider_id,
COUNT(*) as duplicate_count,
GROUP_CONCAT(id) as stage_ids,
GROUP_CONCAT(name) as stage_names
FROM stages
GROUP BY crm_configuration_id, crm_provider_id
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC;
select * from stages where id IN (14898,14907);
select * from business_processes;
SELECT *
FROM crm_configurations
WHERE team_id IN (
SELECT team_id
FROM crm_configurations
GROUP BY team_id
HAVING COUNT(*) > 1
)
ORDER BY team_id;
SELECT *
FROM teams
WHERE crm_id IN (
SELECT crm_id
FROM teams
GROUP BY crm_id
HAVING COUNT(*) > 1
)
ORDER BY crm_id;
# [PASSWORD_DOTS]
select * from crm_configurations where provider = 'integration-app';
SELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 [EMAIL]
select * from activities where crm_configuration_id = 358 order by actual_end_time desc;
select id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;
select * from team_features where team_id = 358;
select * from activity_summary_logs;
select * from teams where id = 406;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, [EMAIL]
select * from activities where crm_configuration_id = 202 order by actual_end_time desc;
SELECT * FROM users where id = 14637;
SELECT * FROM teams where id = 267;
SELECT * FROM groups where id = 1118;
select g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a
inner join users u on u.id = a.user_id
inner join groups g on g.id = u.group_id
where a.crm_configuration_id = 202
and a.is_internal = 0
and (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')
and a.type = 'conference'
and a.status != 'completed'
and a.external_id is not null
order by a.scheduled_start_time desc;
SELECT * FROM activities
WHERE crm_configuration_id = 202
AND status IN ('completed', 'failed')
AND recording_state != 'stopped'
AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
AND (is_private = 0 OR user_id = 14637)
AND (
(
actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
) OR (
actual_start_time IS NULL
AND type IN ('sms-outbound', 'sms-inbound')
AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND NOT EXISTS (
SELECT 1
FROM tracks
WHERE
tracks.activity_id = activities.id
AND tracks.type IN ('audio', 'video')
)
ORDER BY actual_end_time DESC;
SELECT DISTINCT
a.*
FROM activities a
INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
WHERE
a.crm_configuration_id = 202
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 14637
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND a.user_id = 14637
)
)
ORDER BY a.actual_end_time DESC
;
SELECT DISTINCT a.*
FROM activities a
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams t ON u.team_id = t.id
# INNER JOIN tracks tr ON a.id = tr.activity_id
# INNER JOIN groups g ON u.group_id = g.id
WHERE 1=1
AND t.id = 267
# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND tr.type NOT IN ('audio', 'video')
AND (
a.is_private = 0
OR a.user_id = 14637
)
AND (
(a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')
OR (
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'
)
)
# and NOT EXISTS (
# SELECT 1
# FROM tracks t
# WHERE t.activity_id = a.id
# AND t.type IN ('audio', 'video')
# )
ORDER BY a.actual_end_time DESC;
SELECT * FROM tracks WHERE activity_id = 26485995;
select a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a
inner join users u on u.id = a.user_id
where a.crm_configuration_id = 202
# and a.is_internal = 0
and (a.actual_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')
and a.type IN ("softphone","softphone-inbound","conference","sms-inbound")
and a.status IN ('completed', 'failed')
# and a.external_id is not null
order by a.actual_end_time desc;
select * from activities a where a.crm_configuration_id = 202
and a.actual_start_time between '2025-03-20 00:00:00' and '2025-03-21 00:00:00'
# AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
select g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a
inner join users u on u.id = a.user_id
inner join groups g on g.id = u.group_id
where a.crm_configuration_id = 202
and a.is_internal = 0
and (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')
and a.type = 'conference'
and a.status != 'completed'
and a.external_id is not null
order by a.scheduled_start_time desc;
SELECT * FROM teams WHERE name LIKE '%Tourlane%';
SELECT * FROM crm_fields WHERE crm_configuration_id = 209 and object_type = 'opportunity';
SELECT * FROM crm_field_data WHERE crm_field_id = 98809;
select * from users where status = 1 AND timezone = 'MDT';
select * from opportunities where id = 3769814;
select * from deal_risks where opportunity_id = 3769814;
select cp.* from crm_profiles cp
join users u on cp.user_id = u.id
join crm_configurations crm on cp.crm_configuration_id = crm.id
where crm.provider = 'hubspot' AND u.status = 1 AND log_notes != 'none';
select * from crm_fields where id = 154575;
select * from team_features where feature = 'SUPPORTS_SYNC_MISSING_CALL_DISPOSITIONS';
SELECT * FROM teams WHERE id = 176; # crm 148
select * from activities where crm_configuration_id = 148 and provider = 'hubspot' order by id desc;
select * from activity_providers where provider = 'amazon-connect';
select * from crm_fields cf
join crm_configurations crm on crm.id = cf.crm_configuration_id
where crm.provider = 'hubspot' and cf.object_type IN ('account', 'contact');
# [PASSWORD_DOTS]
SELECT * FROM users WHERE id IN (15415, 15418);
SELECT * FROM groups WHERE id IN (1805,1806);
SELECT * FROM playbooks WHERE id = 1860;
SELECT * FROM playbook_categories WHERE id = 38634;
SELECT * FROM crm_fields WHERE id = 189962;
SELECT * FROM teams WHERE name = 'Pulsar Group'; # 472, 380, 15138 [EMAIL]
SELECT * FROM crm_profiles WHERE user_id = 15415;
SELECT * FROM social_accounts WHERE sociable_id = 15415 and provider = 'salesforce';
select * from sidekick_settings where team_id = 472;
SELECT * FROM activities WHERE uuid_to_bin('452c58c7-b87c-4fdd-953e-d7af185e9588') = uuid; # 28617536, user: 15418
SELECT * FROM activities WHERE uuid_to_bin('399114ee-d3a8-458c-bff5-5f654658db0a') = uuid; # 28344407, user: 15415
SELECT * FROM activities WHERE uuid_to_bin('f0aa567f-0ab1-4bbb-96aa-37dcf184676b') = uuid; # 28580288, user: 15415
SELECT * FROM activities WHERE uuid_to_bin('50c086b1-2770-4bca-b5ae-6bac22ec426b') = uuid; # 28566069, user: 15415
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%TeamTailor%'; # 109, 218, 13969, [EMAIL]
select * from crm_configurations where id = 218;
SELECT * FROM activities WHERE uuid_to_bin('e39b5857-7fdb-4f5a-951a-8d3ca69bb1b0') = uuid; # 28338765
SELECT * FROM users WHERE id IN (13232, 13230);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 109
and sa.provider = 'salesforce';
0057R00000EPL5HQAX Inez Ekblad
1091cb81-5ea1-4951-a0ed-f00b568f0140 Triman Kaur
SELECT * FROM crm_profiles WHERE user_id IN (13232, 13230);
############################################################################################
SELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939 00UVg00000FLvnSMAT
SELECT * FROM crm_field_data WHERE activity_id = 28655939;
SELECT * FROM crm_fields WHERE id IN (94491,94493,94498);
SELECT * FROM users WHERE id = 13658;
SELECT * FROM teams WHERE id = 109;
SELECT * FROM crm_configurations WHERE id = 218;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 109
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Strengthscope%'; # 481, 390, 15420, [EMAIL]
SELECT * FROM stages WHERE crm_configuration_id = 390;
select * from business_processes where team_id = 481 and crm_configuration_id = 390;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 481
and sa.provider = 'salesforce';
SELECT * FROM users WHERE id = 15780; # team 462
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 462
and sa.provider = 'hubspot';
select * from teams where id = 495;
SELECT * FROM users WHERE id = 15794;
select * from social_accounts where sociable_id = 15794;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Flight%'; # 427, 333, 13752
SELECT * FROM accounts WHERE team_id = 427 and crm_provider_id = '668731000183444517';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Group GTI%'; # 495, 407, 15794
SELECT * FROM activities WHERE crm_configuration_id = 407
and status = 'completed' and type = 'conference'
order by id desc;
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 permission_role;
select * from activities where crm_configuration_id = 407 and status = 'completed' order by id desc;
SELECT * FROM activities WHERE id = 29512773;
SELECT * FROM activities WHERE id IN (29042721,28991325,29002874);
SELECT al.* from activity_summary_logs al join activities a on a.id = al.activity_id
where a.crm_configuration_id = 407
# and a.id IN (29042721,28991325,29002874);
SELECT * FROM users WHERE id = 15794;
SELECT * FROM users WHERE team_id = 495;
SELECT * FROM social_accounts WHERE sociable_id = 15794;
SELECT * FROM opportunities WHERE team_id = 495 and name like '%OC:%';
SELECT * FROM contacts WHERE team_id = 495;
SELECT * FROM leads WHERE team_id = 495;
SELECT * FROM accounts WHERE team_id = 495;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 407;
SELECT * FROM crm_fields WHERE crm_configuration_id = 407;
SELECT * FROM crm_configurations WHERE id = 407;
SELECT * FROM opportunities WHERE team_id = 495 and close_date BETWEEN '2025-06-01' AND '2025-07-01'
and user_id IS NOT NULL and is_closed = 1 and is_won = 1;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Hamilton Court FX LLP%'; # 249, 187, 10103
SELECT * FROM activities WHERE uuid_to_bin('4659c2bb-9a49-484e-9327-a3d66f1e028c') = uuid; # 28951064
SELECT * FROM crm_fields WHERE crm_configuration_id = 187 and object_type IN ('tasks', 'event');
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Checkstep%'; # 325, 256, 11753
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 325
and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid; # 28611085
SELECT * FROM activities WHERE uuid_to_bin('980f0336-840b-4185-a5a9-30cf8b0749a8') = uuid; # 28719733
SELECT * FROM activity_summary_logs where activity_id = 28719733;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 356, 9444
SELECT * FROM activity_summary_logs where sent_at BETWEEN '2025-06-09 11:38:00' AND '2025-06-09 11:40:00';
SELECT * FROM leads WHERE crm_configuration_id = 356 and crm_provider_id = '230045001502770504'; # 823630
select * from activities where crm_configuration_id = 356 and lead_id = 841732;
SELECT * from activity_summary_logs al join activities a on a.id = al.activity_id
where a.crm_configuration_id = 356;
select * from activities where crm_configuration_id = 356
and actual_end_time between '2025-06-09 11:00:00' and '2025-06-09 12:00:00'
order by id desc;
select * from accounts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;
select * from leads where crm_configuration_id = 356 and crm_provider_id = '230045001514275654' order by id desc;
select * from contacts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;
select * from opportunities where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;
select * from team_features where team_id = 260;
select * from features where id IN (1,2,4,6,18,19,20,9,10,3,23,24,25,26,27);
SELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid;
select * from crm_fields;
select * from crm_layout_entities;
SELECT * FROM teams WHERE name LIKE '%Optable%';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Teamtailor%'; # 109, 218, 13969
SELECT * FROM crm_configurations WHERE id = 218;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 109
and sa.provider = 'salesforce';
SELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939
SELECT * FROM crm_field_data WHERE activity_id = 28655939;
SELECT * FROM crm_fields WHERE id in (94491,94493,94498);
select * from teams where crm_id IS NULL;
SELECT * FROM activities WHERE uuid_to_bin('71aa8a0c-9652-4ff6-bee7-d98ae60abef6') = uuid;
# [PASSWORD_DOTS]
select * from team_domains where team_id = 399;
SELECT * FROM teams WHERE name LIKE '%Rydoo%'; # 399, 318, 13207
select * from calendar_events where id = 5163781;
SELECT * FROM activities WHERE uuid_to_bin('be2cbc52-7fda-46a0-9ae0-25d9553eafc0') = uuid; # 29443896
SELECT * FROM participants WHERE activity_id = 29443896;
select * from contacts where crm_configuration_id = 318 and email = '[EMAIL]';
select * from leads where crm_configuration_id = 318 and email = '[EMAIL]';
select * from activities where user_id = 14937 order by created_at ;
select * from users where id = 14937;
select * from contacts where crm_configuration_id = 318 and email LIKE '%@strawberry.se';
select * from opportunities where crm_configuration_id = 318 and crm_provider_id = '006Sf00000D1WOAIA3';
select * from activities a join participants p on a.id = p.activity_id
where crm_configuration_id = 318 and a.updated_at > '2025-06-23T08:18:43Z';
# [PASSWORD_DOTS]
SELECT * FROM opportunities WHERE team_id = 379 and crm_provider_id = '39334518886';
SELECT * FROM opportunities WHERE team_id = 379 order by id desc;
SELECT * FROM teams WHERE id = 379;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 379 and sociable_id = 13852
and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE id = 307;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 307;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1027;
SELECT * FROM crm_fields WHERE crm_configuration_id = 307
and id IN (144750,144855,145158,155227);
SELECT * FROM activities;
select * from activities
where created_at > '2025-07-01 00:00:00'
# and created_at < '2025-08-01 00:00:00'
and type not in ('email-outbound', 'email-inbound')
and account_id is null
and contact_id is null
and lead_id is null
and opportunity_id is not null
;
SELECT * FROM activities WHERE id IN (25344155, 25344296, 25501909, 28692187);
SELECT * FROM crm_configurations WHERE id in (335,301,200);
select * from crm_fields where crm_configuration_id = 230 and crm_provider_id = 'Age2__c';
SELECT * FROM teams WHERE name LIKE '%Resights%';
select * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';
select * from crm_configurations where provider = 'bullhorn'; # 344
select * from teams where id IN (442);
select * from activities
where crm_configuration_id = 177
and provider = 'amazon-connect'
order by id desc;
# and source <> 'gong';
select * from activity_providers where provider = 'amazon-connect';
SELECT * FROM activities WHERE uuid_to_bin('cec1993b-a7e5-4164-b74d-d680ea51d2f2') = uuid;
select * from crm_configurations where store_transcript = 1;
SELECT * FROM teams WHERE id IN (80);
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Sedna%'; # 277, 213, 12594
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 277
and sa.provider = 'salesforce';
select * from activities where crm_configuration_id = 213 and account_id = 2511502;
select * from crm_configurations where id = 213;
SELECT * FROM activities WHERE uuid_to_bin('35aa790a-8569-4544-8268-66f9a4a26804') = uuid; # 33981604
SELECT * FROM participants WHERE activity_id = 33981604;
SELECT * FROM crm_fields WHERE crm_configuration_id = 337 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 431
and sa.provider = 'salesforce';
SELECT * FROM activities WHERE uuid_to_bin('b5476c7d-19a8-491b-869d-676ea1e857b6') = uuid; # 33997223
select * from activity_summary_logs where activity_id = 33997223;
select * from activity_notes where activity_id = 33997223;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Abode%';
select * from features;
select * from teams t
where t.status = ...
|
PhpStorm
|
faVsco.js – ResponseNormalize.php
|
NULL
|
88395
|
|
88394
|
HomeDMsActivityFilesLater..•More+Slack> 0(ah]Fi HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:248 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88394
|
|
88393
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-lProinet vHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimo CimosewhooResponseNormalize.phoCSeMCPono© SyncFieldAction.ohoCSWnCKealCohe wWwK© WebhookSvncBatchProcelisteners> MetadataaMicrationP oedriveEh SalesforcealeeldsaOpoortunityVatchenOpportunitySyncStrategyProsoec SaarchStrateoSameatitite@ Client.phpC DecorateActivity.php( DeletcObiectsTrait.phposwan ntone non© PayloadBuilder.phpc) Profile.php© QueryBuilder.php© QueryHandler.phpeQuerviterator.oh© QueryResults.php© Service.php© SyncBatchRedisService.pth TraitsC BaseClient oho( CrmActivitvProviderinteorateCCWCMWMoron©rmobiectctesower.on©.DefaultProsoectSearchStrat.C mallteloer.ond3Findeproscectinterace.onoC) LavouMansoe onoexisiinastaad10.02.23 VasilevDaeosnszol13.10.25 Nikolov10.09.25 iliar240418 Graham24.04.18 Graham190218 Grahan121025 Nikolo20418Grahan19.03.18 Graham20418olahan3.10.252.10.2520.10.21 Graham2.10.25170385 dlian1604.75 Ivanov210 252.04,18Graham3.10.29204,18Graham19.03.18 Graham04418Grahamcrahem2.04.18Graham100218 GrabanC Opportun tvActvitwlatcheeeennortur wewn.Ctestomedrnenont tschd nhrHe OrnenontCostrhSrond nhnWindowServiceTestTO0У L7Inu Lo mey koule[PHONE]0140340440S407408)426428CMatchiet witermints che= IaravellogSF jminny@localhost)© RecordSelector.phg© Activity.phoC) Team.phd# HS local [liminny@localhost# ConbocrhouA console (EU) x iii users (EU)# console (STAGINGTx: AutovSo liminnyBROER PYTnane, M.emare031 A9 A29 V3 /109 A Vclass Service extends BaseService implements01 A7 A149 V1V33 /1 A v 170%public function importStages(?array Stypes = null, ?string SnissingStageNane = nul)): ?Stage1706— 1708SELECT * FRON teans WHERE name LIKE "stounlanes: # 187, 289, 8158SEEiNTUse the Hubspot API client instead of the SDK crmPipelines ) methodencooinr set..certen spineunessndodnro17161711Spipelineskesponse = Sthis->client->getinstance()->getelient()->peguest(method: "BET" , Sen 1712Spipelines = Spipelineskesponse->data->results;carch litecnestSycent sonl Rarkennast Saycentonсллou pexсeaeoth1719foreach (Spipelines as Spipeline) ‹$stages = O— 1715-1728=1720$p = ResponseNornalize::normalizePipeline(Spipeline):SbusinessProcess = Sthis->confiq->businessProcesses@->update0rCreateCd1, t= his-xean->1d.= mb_strinwidth(Spf"label"=> BusinessProcess::TYPEOPPORTUNTTY=> Sol'active').Start 8rwiodt58)=1727=1729=173017391=1732I A recoro tyte re resityp clone of the business process, used to store which recond USe 17s// Create/update record type cloneSthisosconfiaesnecondTvnes(l-sundatehofceatech1736E17571738= 1755etaewdthssolahe"is_selectable=> $p['active'],hetnsce noocnee s Chuesnneepnocneeesdo% oubalD):=1742=1742— 1743-1745aniheCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEMrenasisa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:select * fron accounts where id = 4156632:select * fron opportunities where id = 4843610:#updateacove#"stage_id' = 132730c0un8-4300-4"contact_id' ="updated at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91*:select * fron actviates order oy 1d desc;select * fron users where nane loike "subraaSELECT * FROM opportunities HERE unid to_ bin('84a9cfad-2c87-4453-S|select * fron teans where 1d = 557select * fron stages where tean_id = SSS;SETSTMTCONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSElhenasa.*,honnen siil coesasccounteeJOIN users u on u.id = sa.sociable.idahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubspot":select id, is_closed, is_won, stage_updated_.at, crm_provider_id, stclose date, forecast category, deleted at, created_at, remotely-crtfron opportunities where tean id = SSS and stageid = 28616 order_Stages - fetch all existing stages upfront to avoid N+1 queriesSexistingStages = $this->config-›stages()->withTrashedO->where("type", Stage::TYPE_ OPPORTUNITY.->getO->kevBy(*crn_providerid')select id. crn-provider id, nane, probability, undated at. deletes=1748Gnon etanodwhere id = 28616foreach (Sof"stages'] as SdealStage)f=Cecsdales Orcnnworeebeeionhmwesotino ooro272464f100 JY-19613 retry on unexpected exception-• git shơw 874C3cea56 - app/Services/Crm/Hubspot/Service-php | grep -A 48 "inportStages"• git show Sfd720fd5b:app/Services/Crm/Hubspot/Service.php | grep -A S8 "function importStages"public function inportStages(farray Stypes u nutl, Zstring SmissingStageNane • null): 75tagonestooee nolt//Use the HubSpot APT client instead of theOokerpinahnado cathoeue ipea e gone inara ponaen a e vratance() -egetCLtent() -request CET:, sendpse);nand git, greo, ta• git show 5td720fd5b:app/Services/Crm/Hubspot/Service.php | grep -A 78 "function importStages" | tail -2:1,'em provider_td' = Ss("1d*"tean_io8, 1915"is_selectableoralabfistyA est'orabahs kew'l 190The probability logic was identical in Nov 2025. Now let me check norealizeDealStage at that timeCommand eit, orec• qit shơw 51d7201d5b:app/Services/Crm/Hubspot/ResponseNormalize.php | grep -A 20 *normalizeDea lStage)public static function normalizebealStage(array|object SdealStage): arraySdata = selt::toArray(SdealStage):displayorder* (ant) (Sdatal"displayOrder") 77 ®)Also loenical. Now exmecoeknelockoealSy toclonest-n00on=n is Wiha ne Now Wo ouKimooturoocho delne oata, Was neledittorant sndnd nt he notkM st thot tmatgtep/ servieisne-bspo esereceices/2o/eusut/S grtee: pPgl xeats -De nes Eropott sh 2a/dev/null | head -solnnthnoXoeCtty lwew ou teoueet today lhay• OKwweunamet4 spad...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88393
|
|
88392
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
rapstomEV faVsco,ls ~ProjectvCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPono© SyncFieidAction.phpCSWnCKealCohe wWwK© WebhookSyncBatchProce?—neo aionhelisteners> MetadataMigrationP oedriveSalesforceafeldsOpportunityMatcherOpportunitySyncStrategyProspectSearchStrategy© Cient.php© DecorateActivity.phpG DeleteObjectsTrait.phpoewanarinithooe nha© PayloadBuilder.php© Profile.php©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.php© SyncBatchRedisService.ptTraits© BaseCllent.phpCwastemoeene© CachedCrmServiceDecoratorexisiinastaad10.02.23 Vasilev20438Graham24.04.18 Graham24.04.18 Graham3.10.253.10.2513.10.25 Nikolov13.10.25 Nikolov10.09.25 ilian24.04.18 Graham24.04.18 Graham19.03.18 Graham12.10.26 Nikalm2.04.1819.03.18 Graham2.04.18 Graham3.[IP_ADDRESS].10.2520.10.21 Graham17.03.25 ilian2.10.2520438Grsham3.10.25104418Grsham19.03.18 Graham70413GrhamCrmactivity ProviderintegrateCCWCMWMoron20.107 Graham©rmobiectsteso wer.ono© DefaultProspectSearchStrateC Emal telcerond3sindeProscectinternce.onoC) LavouMansoe onoMatchdomsinsysmainteneC Opportun tvActvitwlatche204.187101202.10.2581192.04.18Graham19.03.18 Grahameennortur wewn.CtestomedProspectCache.phpHe OrnenontCostrhSrond nhn4.05.26 Ivanov4.05.26 Ivanovntity // View pull request (today 16:12)WindowU ServiceTest ~Thu 28 May 20:01:17+0.386 Ct387389391393401403[PHONE]28RecordSelector.php© Team,phpE IaravellogA HSJJocal (jiminny@localhost]A console (STAGING]CascadeA console (EU] x E users (EU)les Orcnnworeebeeionhomwwtino ooooThc AutoORDER BY t.name, u.email;• git show 874C3cea56 - app/Services/Cra/Hubspot/Service-php | grep -A 40 "InportStages"class Service extends BaseService inplementspublic function inportStages(?array $types = null, ?string SnissingStageNane = null): ?Stage170601 47 A149 X1 X33 21 A V 1707-17081709SnissingStage = null;17101711try (1712// Use the HubSpot API client instead of the SDK crmPipelines() nethod1713Sendpoint = self::getDealsPipelinesEndpointO):1714SpipeLinesResponse = Sthis-scLient->getInstance() -»getCLient () ->gequest ( method: "GET' , Sen 1715Spipelines = SpipelinesResponse->data-›results;} catch (RequestException|BadRequest Sexception) (-1717ahonspxceor othSe jiminny~031 49 A29 X3 X109 A VE171s=1720foreach (Spipelines as Spipeline) (Sstages = (1:Sp = ResponseNornalize: :normalizePipeline(Spipeline);// Create/update business process for this pipelineSbusinessProcess = Sthis->config->businessProcesses() ->update0rCreate(E=1727-1728-1725=173€asose8eston=> mb_strimwidth(Sp( 'Label'],start: 0,= Business?rocess.:PE OpPoRTumena>> Spl'active'].E1734-1733=17391736Janecond typesis renlly a alone of the business process, lused to stone wich necond1735I/ Create/update record type clone1738Sthinosconfia-snecondTvoes @-sundate0rGeeateChE17391740=1742Sthis->tean->id,nana=> mb_strimwidth(Sp['label'], (start 0, (width: 150),"is„selectable'=> Sp['active'],business_process_id' = SbusinessProcess->id 2? null,—1742=1743=1744=17451746 21748SELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SELECTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-u.enail,sa.x,t.ouner_id FROM social_accounts saJOIN users u on u.id= sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce':• qít show 516729105b:ao0/Services/Crm/Hubspot/Service,pho | qreo -A 59 "function iecortStaoes"publie function InportStages(7array stypes = null, Zstring SaissingStageName = null): 75tageSaissingStage = null;Se use the tuosSpipelTnesRes ponge=select * fron activities where id = 31264367:select * fron contacts where id = 6331639;select * fron accounts where id = 4156632;select * fron opportunities where id = 4843610;# updateacove300n8-4300-4"contact_id' = 6.#'stage_id' = 13273,"updated_at' = 2026-05-22 07:16:• git show 51d7281d5b:app/Services/Cmn/Hubspot/Service-php | grep -A 70 "function inportStages" | tail -25craprovloer10 = S$10Batrana raat): 8: 18,select * fron text_relays where created_at > ^2026-05-01';select * fron activities order by id desc;is l'brobabtlity'1 2109)Uhe proosbility looic was idenucal in Nov 2020. now let me check nora lizcoea lStage at that ümeselect * fron users where name like "XSubrak';SELECT * FROM opportunities WHERE wuid_to_bin('04a9cfad-2c87-4453-$select * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:lhenasa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id= sa.sociable_idJOIN teans t 1.n<->1: on t.id = u.tean_idWHERE u.tean_id = 100 and sa.provider = "hubspet":• git show 51d728fdSb:app/Services/Crm/Hubspot/ResponseNormalize-php | grep -A 28 "normalizeDealStage"public static funczion nomalizevealStage(array|object sdealstage): array1d' P Sdatal'stageid'!, 27 nult,(int) (Sdata('display0rder'] 27 ®),Also identical. Now let me check the getDealsPipelinesEndpoint - this is what the Nov 2025 bulk import used to fetch pipeline data. Was there aCommand git, xargs, heado git oeserietine -bspor e/Seciees/2/bsp/S giee- ertsP-pl reseropoit shos2>/dev/null | head -sselect id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 5SS and stage_id = 28616 order_*select id, crn_provider_id, nane, probability, updated_at, deleterefron stageswhere id = 28616;Run xe (Skip// Stages - fetch all existing stages upfront to avoid N+1 querieses = Sthis->config-›stages()›withTrashedO)->ahere('type', Stage:: TYPE_OPPORTUNITY)Ask anything (XOL)"eoohAdhetKwweuname• O2 4 spac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88392
|
|
88391
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:178 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88391
|
|
88390
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
1
7
149
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
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\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
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\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
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_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @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
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData 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;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_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 = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'ac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88390
|
|
88389
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-lHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.pho© SyncFieldAction.ohoCSWnCKealCohe wWwK© WebhookSvncBatchProcelisteners> MetadataaMicrationP oedriveEh SalesforceafeldsaOpoortunityVatchenOpportunitySyncStrategyProsoectSaarchstrateosametiteC DecorateActivity.php( DeletcObiectsTrait.phpoewanarinithooe nha© PayloadBuilder.phpc) Profile.phpe QueryBulderonp© QueryHandler.phpeQuerviterator.oh© QueryResults.php© Service.php© SyncBatchRedisService.pth TraitsC BaseClient ohoCrmActivityProviderinteorateCCnlACMiWMoh©rmobiectsteso wer.onoC. DefaultProsoectSearchStrateC mallteloer.ond3Findeproscectinterace.onoC) LavouMansoe onoexisiinastaad10.02.23 VasilevDaeosnszolGraham811192.04.18Graham190218 Graham4.05.26405284.05.26A05284.05.262.10.253.10.2512.10-254.05.264.05.264.05.264.05.264.05.26405.2540525405.2617.02.25 iliar4.05.26Matchdomsinsysma inteaneC Opportun tvActvitwlatcheee2A419Graham10.02 18 Grabameennortur wewn.Ctestomed20419Grahamrnenont tschd nhrHe OrnenontCostrhSrond nhnGraham100516 CrkamAottylwiew outrenuaet todayRay422424426428430439442451457sraveloe© RecordSelector.phgC) ACUVIY.or.pC) Team.phd# HS local [liminny@localhostA console (EU) x iii users (EU)(© HubspotLastModifiedCreatedRecentlyOpenSyncStrategy.phcconsole (STAGINGclass Service extends BaseService implements01 A7 A149 V1V33 /1 A v 170%public function importStages(?array Stypes = null, ?string SnissingStageNane = null): ?Stage1706—1708crn_provider_1d => Spl'1d"J1, thssosrearosdeteondoseesrwdthisoahe"e'1s_selectable'=> Spl'active"]buesnecs anocecs a' =s ShussnessProcessc5d 22 mulil1):Stages - fetch all existing stages upfront to avoid N+1 queriesxistingStages = Sthis->config-›stages->withTrashedOanchetwoeStage:: TYPE._OPPORTUNITY,foreach (Spl"stages' as SdealStage) 4$s = ResponseNornalize::normalizeDeal Stage(SdealStage)/** @vac ?Stage SexistingStage */SexistingStage = SexistingStases-saetSsd0// Restore soft-deleted stages that are now active in HubSpotif (SexistinoStage?->trashedO &s Ssf'actsive' 1)losert shace mndanes corrodelared necords withoun rastonsno thentSstage = Sthis->config->stages()->withTrashed()->update0rCreateClMmeostasrosd=> ch staseudath(sefilabel !1lwidth: 58).eraedrhselnhe""yne"=> Stage:: TYPE_OPPORTUNITY,=> $s['display0rder'].1e colectahla=> $s['active']tnrahshsl4tw,=> $s['probability') * 100171612111— 1715-1728= 1726=172- 1722=172-172)=173017391E1732—1733-173581736E17571738= 17551746=1742=1742=114-17451746 %Tx: AutovSo liminnyvBROER PYTnane, M.emare031 A9 A29 V3 /109 A VSELECT * FRON tEaNS WHERE name LIKE "Stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEMrenasisa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1dWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:Belecekx tron accoun ancheo- 450054select * fron opportunities where id = 4843610:#Uodare#"stage_id' = 132730c0un8-4300-4"contact_id' ="updated.at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91°:select * fron actviates order oy 1d desc;select * fron users where nane tuike "subraaSELECT * FROM opportunities WHERE unid to_bin('04a9cfad-2c87-4453-$select * fron teans where 1d= 555%select * fron stages where tean_1d = 555:SETSTMTCONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSEsa.*,onnenstil socal nccounteeJOIN users u on u.id = sa.sociable_idahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubspot":select id, is_closed, is_won, stage_updated.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 orderselect sid, ern-provider id, nane, probability, undated at, deletos:—1/40fron stageswhere id = 28616$f (SnissingStageNane aas Ssfid'n ‹SmissinaStage = Sstage:ServiceTestCascadeles Orcnnworeebeeionhomwstotino oosoa/huospot/Service.php b/app/Services/Cra/Hubspot/Service.phgNow let me look at the Nov 2025 bulk import - what importStages looked like at that time:• git log -oneline -before="2025-11-19" --after="2025-09-01" -- app/Services/Crm/Hubspot/Service-php | head -Sbod is vertertaskexcutd eeseptionsretry on unexpected exceptionsair shon slcteas, — aoo/eruiicesherHunsoor/Service,oho lared eA "eoorraoss.• qát show 516729105b:a00/Services/Crm/Hubspot /Service,pho | qreo -A 59 "function iecortStaoes"publie function inportstages(zarray Stypes = null, Zstring SaissingStageNane = null): 75tage// Use the HubSpot API client instead of the SDK crmPipelines() methoSoloeiinesResponse e SthisesCLtent-soetInstance()-sgetCLient ()-srequest ('GST', Sendooint)soloelines = spfoelinesResponse-sdata-sresults:.• gít shơw 5fd720fd5b:app/Services/Crm/Hubspot/Service.php | grep -A 70 "function importStages" | tail -2.'cr provider id' = ss('id')tean_1dHleutt e 1odThe probability logic was identical in Nov 2025. Now let me check normalizeDealStage at that time0 git show 5fd720fdSb:app/Services/Crm/Hubspot/ResponseNormalize.php | grep -A 20 "normalizeDealStage)rt aeuthientuniinu Lo mey koulu+0.Kwweuname(Run 33-) (Skip• Ot4 spag...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88389
|
|
88388
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:01:018 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88388
|
|
88387
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
1
7
149
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
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\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
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\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
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_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @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
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData 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;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_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 = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'ac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88387
|
|
88386
|
rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-lpr rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-lproidetHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.phoCSeMCPono© SyncFieldAction.ohoexisiinastaad10.02.23 Vasilev© synckelateoncuvnymanas 24.01.25 Papazov© WebhookSvncBatchProce17.03 25 ianlisteners> MetadataaMicrationP oedriveEh SalesforceafeldsaOpoortunityVatchenOpportunitySyncStrategyProsoec SaarchStrateosametiteê crant nhoC DecorateActivity.php( DeleteObiactsTrait.phpoewanarinithooe nha© PayloadBuilder.phpc) Profile.php© QueryBuilder.php© QueryHandler.php© Queryiterator.php© QueryResults.php© Service.php© SyncBatchRedisService.ptin TraitsRaseeentonoCrmActivityProviderinteorateCCnlACMiWMoh©rmobiectctesower.onC. DefaultProsoectSearchStrateC mallteloer.ond3sindeProscectinternce.onoC) LavouMansoe ono16.0425 wanok710552.0418204.18Graham19.03.18 Grahan2.04.18Olanidi20.10.21 Grahan710262.04.18Grahan2.10.252.10.258.11.182.04.18Graham19.03.18 Grahan4.05.264.05.264.05.26405.262.10.297-1025A05.28A05.28A05.28C Opportun tvActvitwlatcheeeennortur wewn.Ctestomedrnenont tschd nhrHe OrnenontCostrhSrond nhnWindowServiceTestTO0У L7Thu 28 May 20:00:5%+0.Clostoeas noseiveioe40$«11[PHONE]38440442446448sraveloe© RecordSelector.phgC) ACUVIY.or.pC) Team.phd# HS local [liminny@localhostA console (EU) x iii users (EU)console (STAGINGclass Service extends BaseService implements01 A7 A149 V1V33 /1 A v 170%public function importStages(?array Stypes = null, ?string SnissingStageNane = null): ?Stage1706— 1708tean_idnamel=> Sthis->tean->id,3>nhstrirwidthSol"abelestart: 8,wiohSen171612111"type"=> BusinessPnocess: :TYPE_OPPORTUNITY,=> Sp['active'),1713A record type is really a clone of the business process, used to store which record use-/eCreate/update record type cloneSthis->config->recordTypes@->update0rCreatel'cre provider 1d' => Sp('id')— 1715-1728= 1726'tean id= Scns->cean->10,=> mb strinwidth(Sp('label').=> Sp('active')"business process_id' => SbusinessProcess->id ?? nullwidth: 158)172:= schis->cont 10=>scageslo->withTrashedOsnhene("type" Staoc:-TYPE OpPORTUNITy)->0601kewswleeonorowidero=172≤1727=1729=173017391E17321733oneach astaops.asheasradeSs= ResponseNonnalize::normaLizeleal Staae(SdealStace),=1735/** @vac ?Stage SexistingStage *,SeyistainoStaopSoyiistainaStaaesosaet/Sch.d// Restore soft-deleted stages that are now active in HubSpot1f (SexistingStage?->trashed() && $s['active']) (SeyistnoStanp.sractoneoE17571738= 17551703=174=1742= 1143/ Upsert stage (updates soft-deleted records without restoring thenSstage = Sthis->confiq->stages@->withTrashed@->update0rCreate"crnprovider id' => Ss(id'.= 1743—1/40—Cahtedwheda= mb_strinwidth(Ss("label'= mb_strinwidth(Ssf"label'MAN 1041Tx: AutovSo liminnyvBROER PYTnane, M.emare031 A9 A29 V3 /109 A VSELECT * FRON tEaNS WHERE name LIKE "Stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEMrenasisa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1cWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:seleekx tron account anchs 0-450054select * fron opportunities where id = 4843610:#Uodare#'stage_id' = 132730c0un8-4300-4"contact_id' ="updated at" = 2826-95-22 07:16:select * trot1text relavs where created at > *2026-95-01°select * fron actviales order oy 1o desciselect * fron users where nane oike SubrasaSELECT * FROM opportunities WHERE wnid to_bin('04a9cfad-2c87-4453-$|select * fron teans where 1d= 555%select * fron stages where tean_1d = 555:SETSTMTCONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSEhonnen siil coesasccounteeJOIN users u on u.id = sa.sociable.igahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubspot":select id, is_closed, is_won, stage_updated.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 orderselect id. con_provider id, name.probabilitv, undated at, deletesfron stageswhere id = 28616Cascadeles Orcnnworeeoeionhomwwtino ooooDatelr Luk Fe0 27 16:87318 2826 -020831t. ComDlowor retum deletedisoor© aft choy 8714617963 -100/Carufcec/Con/Hubsnot/Sarusce.ohdDate:Nhu bếy 5 122215k0 282: 1820vSync Hubspot Active Dealsshdex aittedea/ Stvse/T bepot/Servie, php b/spg/Services/Crm/hubspot/Servie.phpNow lct me look at the Nov 2025 buix import = what inportStages looked like at that timo• git log-oneline -beforea*2025-11-19" -after"2025-09-01" -- app/Services/Crm/Hubspot/Service.php | head -S• git shơw 874C3cea56 - app/Services/Crm/Hubspot/Service-php | grep -A 48 "inportStages• oft show 5f6720fd5bsano/Saryices/Crm/Hubspot /Service,oho I areo -A 59 "function StroortStages"public function inportStages(array Stypes & null, ?string SaissingStagelane • null): 75taggSmissingStage = nullspipe lineskesponse # sthis-setient-sgecinsteceuoooecotenierroudecnooothiesCommand ait. areo, tal0 git show 5fd720fdSb:app/Services/Crm/Hubspot/Service-php | grep -A 70 "function importStages" | tail -25Ask anything (XOL)tylwiew oulteonaet today RayKwweunameRun st= (Skip• Ot4 spad...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88386
|
|
88385
|
Project: faVsco.js, menu
HomeDMsActivityFilesLater Project: faVsco.js, menu
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:00:528 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88385
|
|
88384
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
1
7
149
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
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\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
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\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
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_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @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
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData 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;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_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 = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'ac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88384
|
|
88383
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-lProinet vHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.phoCSeMCPono© SyncFieldAction.ohoexisiinastaad10.02.23 Vasilev© synckelateoncuvnymanas 24.01.25 Papazov© WebhookSvncBatchProce17.03 25 ianlisteners> MetadataaMicrationP oedriveEh SalesforceafeldsaOpoortunityVatchenOpportunitySyncStrategyProsoec SaarchStrateosametiteê crant nhoC DecorateActivity.php( DeletcObiectsTrait.phposwan ntone non© PayloadBuilder.phpc) Profile.php© QueryBuilder.php© QueryHandler.php© Queryiterator.php© QueryResults.php© Service.php© SyncBatchRedisService.ptin TraitsRaseeentonoCrmActivityProviderinteorateCCnlACMiWMoh©rmobiectctesower.onC. DefaultProsoectSearchStrateC mallteloer.ond@. FindeProsoectinterfacc.ohoC) LavouMansoe ono16.0425 wanok710552.0418204.18Graham19.03.18 Grahan2.0418Olanidi20.10.21 Grahan710202.04.18Grahan2.10.252.10.258.11.182.04.18Graham19.03.18 Grahan4.05.264.05.264.05.26405.262.10.297-1025A05.28A05.28A05.28C Opportun tvActvitwlatcheeei lennortur tevnaCtestomiedirnenont tschd nhrHe OrnenontCostrhSrond nhnWindowClostoeas noseiveioe40$«11[PHONE]38440442446448450sraveloe© RecordSelector.phgC) ACUVIY.or.PC) Team.phd# HS local [liminny@localhostA console (EU) x iii users (EU)console (STAGINGclass Service extends BaseService implements01 A7 A149 V1V33 /1 A v 170%public function importStages(?array Stypes = null, ?string SnissingStageNane = null): ?Stage1706— 1708tean_idnamel=> Sthis->tean->id,3>nhstrirwidthSol"abelestart: 8,wiohSen171612111"type"=> BusinessPnocess: :TYPE_OPPORTUNITY,=> Sp['active'),1713A record type is really a clone of the business process, used to store which record use-/eCreate/update record type cloneSthis->config->recordTypes@->update0rCreatel'cre provider 1d' => Sp('id')— 1715-1728= 1726'tean id= Scns->cean->10,=> mb strinwidth(Sp('label').=> Sp('active')"business process_id' => SbusinessProcess->id ?? nullwidth: 158)172:= schis->cont 10=>scageslo->withTrashedO->where('type', Stage:: TYPE_OPPORTUNITY)->kevßv("con croviden id'),=172≤1727=1729=173017391E17321733oneach astaops.asheasradeSs= ResponseNonnalize::normaLizeleal Staae(SdealStace),=1735/** @vac ?Stage SexistingStage *,SeyistainoStaopSoyiistainaStaaesosaet/Sch.d// Restore soft-deleted stages that are now active in HubSpot1f (SexistingStage?->trashed() && $s['active']) (SeyistnoStanp.sractoneoE17571738= 17551703=174=1742= 1143/ Upsert stage (updates soft-deleted records without restoring thenSstage = Sthis->confiq->stages@->withTrashed@->update0rCreate"crnprovider id' => Ss(id'.= 1743—1/40—Cahtedwheda= mb_strinwidth(Ss("label'= mb_strinwidth(Ssf"label'MAN 1041Tx: AutovSo liminnyvBROER PYTnane, M.emare031 A9 A29 V3 /109 A VSELECT * FRON tEaNS WHERE name LIKE "Stounlanes: # 187, 289, 8158SEEiNTCONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEMrenasisa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1cWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:seleekx tron account anchs 0-450054select * fron opportunities where id = 4843610:#Uodare#'stage_id' = 132730c0un8-4300-4"contact_id' ="updated at" = 2826-95-22 07:16:select * trot1text relavs where created at > *2026-95-01°select * fron actviales order oy 1o desciselect * fron users where nane oike SubrasaSELECT * FROM opportunities WHERE wnid to_bin('04a9cfad-2c87-4453-$|select * fron teans where 1d= 555%select * fron stages where tean_1d = 555:SETSTMTCONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSEhonnen siil coesasccounteeJOIN users u on u.id = sa.sociable.igahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubspot":select id, is_closed, is_won, stage_updated.at, crm_provider_id, stclose date, forecast_category, deleted_at, created_at, remotely_crtfron opportunities where tean id = SSS and stage_id = 28616 orderselect id. crn_provider id, name,probabilitv, undated at, deletesfron stageswhere id = 28616TO0У L7Inu Lo moy kuiuuiseServiceTestCascadeles Orcnnworeebeeionhomwwtino ooooDatelr Luk Fe0 27 16:87318 2826 -020831t. ComDlewor retum deletedisoor+0.© aft choy 8714617963 -100/Carufcec/Con/Hubsnot/Sarusce.ohdDate:Nhu bếy 5 122215k0 282: 1820vSync Hubspot Active Dealsshdex aittedea/ Stvse/T bepot/Servie, php b/spg/Services/Crm/hubspot/Servie.phpNow lct me look at the Nov 2025 buix import = what inportStages looked like at that timo• git log-oneline -beforea*2025-11-19" -after"2025-09-01" -- app/Services/Crm/Hubspot/Service.php | head -S• git shơw 874C3cea56 - app/Services/Crm/Hubspot/Service-php | grep -A 48 "inportStages• oft show 5f6720fd5bsano/Saryices/Crm/Hubspot /Service,oho I areo -A 59 "function StroortStages"public function inportStages(array Stypes & null, ?string SaissingStagelane • null): 75taggSmissingStage = nullspipe lineskesponse # sthis-setient-sgecinsteceuoooecotenierroudecnooothiesCommand ait. areo, tal0 git show 5fd720fdSb:app/Services/Crm/Hubspot/Service-php | grep -A 70 "function importStages" | tail -25Ask anything (XOL)tylwiew oulteonaet today RayRun st= (Skip• OuwnderhimtKaawhirest4 spad...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88383
|
|
88382
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:00:388 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88382
|
|
88381
|
HomeDMsActivityFilesLater..•More+Slack> 0(ah]Fi HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:00:358 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88381
|
|
88380
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
rapstomCoocFV faVsco.|s ~#12121 on JY-20963-fx-lProinet vHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol CimosewhooResponseNormalize.phoCSeMCPono© SyncFieldAction.ohoexisiinastaad10.02.23 Vasilev© synckelateoncuvnymanas 24.01.25 Papazov© WebhookSvncBatchProce17.03 25 ian16.0425 wanoklisteners71055> Metadata2.0418GrahamaMiorationP oedriveEh Salesforce204.18Grahamafelds19.03.18 Grahan2.04.18OlanidiaOpoortunityVatchenOpportunitySyncStrategyProsoectSaarchstrateo20.10.21 Grahan71020sametiteê crant nho2.04.18GrahanC DecorateActivity.php( DeletcObiectsTrait.phposwan ntone non2.10.252.10.258.11.18© PayloadBuilder.php2.04.18c) Profile.php© QueryBuilder.php© QueryHandler.phpeQuerviterator.oh© QueryResults.php© Service.php© SyncBatchRedisService.pth TraitsRaseeentono© BaseService.cho2.10.29Graham19.03.18 Grahan4.05.264.05.264.05.26405.26[PHONE]CrmActivityProviderinteorateA05.28CCnlACMiWMohCermcontcurationSettnosserA05.28©rmobiectctesower.onC. DefaultProsoectSearchStrateA05.28C mallteloer.ond@. FindeProsoectinterfacc.ohoC) LavouMansoe ono8. MatchDomainByEmalllntorfac4052AC Opportun tvActvitwlatcheeeennortur wewn.Ctestomedrnenont tschd nhrHe OrnenontCostrhSrond nhntylwiew oulteonaet today RayWindowTO0У L7Thu 28 May 20:00:33ServiceTest+0.409«11[PHONE]38444446448449CSamviceTestonsraveloe© RecordSelector.phgC) ACUVIY.or.PC) Team.phd# HS local [liminny@localhostA console (EU) x iii users (EU)console (STAGINGTx: AutovSo liminnyvBROER PYTnane, M.emare031 A9 A29 V3 /109 A Vclass Service extends BaseService implements01 A7 A149 V1V33 /1 A v 170%public function importStages(?array Stypes = null, ?string SnissingStageNane = null): ?Stage1706— 1708SELECT * FRON tEamS WHERE name LIKE "Stounlanes: # 187, 289, 8158SEEiNTtean_idnamel=> Sthis->tean->id,3>nhstrirwidthSol"abelestart: 8,wiohSen171612111"type"=> BusinessPnocess: :TYPE_OPPORTUNITY,=> Sp['active'),1713A record type is really a clone of the business process, used to store which record use-/eCreate/update record type cloneSthis->config->recordTypes@->update0rCreatel'cre provider 1d' => Sp('id')'tean id= Scns->cean->10,=> mb strinwidth(Sp('label').=> Sp('active')"business process_id' => SbusinessProcess->id ?? nullwidth: 158)c:= Schis->cont 10->staqcslon->withTrashedO->where('type', Stage:: TYPE_OPPORTUNITY)KewsMleconprowiderooneach salsaopsasSdeaitraaeiSs= ResponseNonnalize::normaLizeleal Staae(SdealStace),/** Bvac ?Stage SexistingStage *,SexistingStage = SexistingStages->get(Ss[*id')):— 1715-1728= 1726TAAA4AR=1729=173017391E1732—1733=173581736E17571738= 1755// Restore soft-deleted stages that are now active in HubSpot1f (SexistingStage?->trashed() && $s['active']) (SexistingStage->restoreo:=174—1742= 1143CONCAT(U.1d, CASE WHEN U.10 = t.ouner_1d THEN" (owner)" ELSEMrenasisa.*t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.soclable_idJOIN teans t 1.nc->1: on t.id = u.team_1cWHERE u.tean_id = 187 and sa.provider = 'salesfonce':select * fron activities where id = 31264367select * fron contacts where id = 6331639:seleekx tron account anchs 0-450054select * fron opportunities where id = 4843610:#Uodare#"stage_id' = 132730c0un8-4300-4"contact_id' ="updated at" = 2826-95-22 07:16:select * fron text relavs where created at > '2926-95-91%select * fron actviates order oy 1d desc;select * fron users where nane oike SubraseSELECT * FROM opportunities HERE unid to_ bin('84a9cfad-2c87-4453-S|select * fron teans where 1d= 555%select * fron stages where tean_1d = 555:SETSTMTCONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSEonnenstil socal nccounteeJOIN users u on u.id = sa.sociable.igahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubspot" :select id, is_closed, is_won, stage_updated.at, crm_provider_id, stclose date, forecast category, deleted at, created_at, remotely-crtfron opportunities where teanid = SSS and stageid = 28616 order_/ Upsert stage (updates soft-deleted records without restoring thenSstage = Sthis->confiq->stages®->withTrashed@->update0rCreate"crnprovider id' => Ss(id'.=1745_1746 v-1748select sid, ern-provider id, nane, probability, undated at, deletos:fron stageswhere id = 28616—Cahtedwheda= mb_strinwidth(Ss("label'= mb_strinwidth(Ssf"label'Cascadeles Orcnnworeeoeionhmwesotino ooro© ait chou c68t849,29 e nno/Senynces/cm//Mubsnot//Service, ohocomnit c6838d8a293577d7c@ac3c46916b88a8dSd0888cAutei Fi Fe 27 16:67918 2426 -0281. comJY-20197 return deleted importditt -git a/app/services/Cra/nuospot/service.php b/app/servaces/cra/Hubspot/Service.php• qit show 87146179ba - app/Services/Crn/Hubspot/Service.php58 12:22:56 2e25 vezove) Jminny- Com»Sune ttosooreowe benksot/Service.php b/app/Services/Crm/Hubspot/Service.phpNow let me look at the Nov 2075 bulk imoort = whatetnoor Stages looked like at that time.Command cir bondalloo wneun —orwo-ire-i9ad00/ervcse/htoscowerce.ohone.d=56072005B JY-1951 Nted SFveraticato0r - check Task or Event y puayate a recordhandle proper not found exceptionshreter on theroested exceotiion• qit show 874c3c0a56 - apo/Services/Crm/Hubspot /Service.php | greo -A 49 "incortStages"© at chou StctzetdSbanoo/Senyiices/Cm/Mubsoot/Seryiicoroho aren cA Sa "tunct ion simoortStaoee"public function inportStages(tarray Stypes = null, Zstring SmissingStageNane = nutl): 7Stagekgimsinee nuiadthy Use the HubSpot APT client instead of the SDK Crnpipelines() methodSorel lne erplifti eroeal ,Poeg 1ntesEod e antoncel) -egetCLient()-arequest( CET*, sendpaint):;Ask anything (XOL)ceodhKwweuname• Ot4 spad...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88380
|
|
88379
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
rapstomEV favscojs ~ProjectvCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPono© SyncFieidAction.phpCSWnCKealCohewW© WebhookSyncBatchProcelisteners> MetadataMigrationP oedriveSalesforcealeeldsOpportunityMatcherOpportunitySyncStrategyProspectSearchStrategy© Cient.php© DecorateActivity.phpG DeleteObjectsTrait.phpoewanarinithooe nha© PayloadBuilder.php© Profile.php©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.php© SyncBatchRedisService.ptTraits© BaseCllent.phpCwastemoeene© CachedCrmServiceDecoratorCrmactivity ProviderintegrateCCWCMWMoron©rmobiectsteso wer.ono© DefaultProspectSearchStrateC Emal telcerond3Findeproscectinterace.onoC) LavouMansoe onoC Opportun tvActvitwlatcheeennortur wewn.CtestomedProspectCache.php(C ProspectSearchScope.phpWindowU ServiceTest ~TO0У L7Thu 28 May 20:00:30+0.exisiinastaadLu.Ulco ropozo19.03.18 Graham2.04.18Graham24.04.18 Graham24.04.lo Olanidn3.10.253.10.2513.10.25 Nikolov13.10.25 Nikolov10.09.25 mla24.04.18 Graham24.04.18 Graham19.03.18 Graham704.18Graham19.03.18 GrahamGrahan3.10.25onowcraham2.10.2517.03.25 lllan16.04.25 Ivanov710252.04.183.10.25Graham2.04.18Graham19.03.18 Graham2.04.18Graham20.10.21 Graham2.10.252.04.18Graham16.04.25 Ivanow2.10.258.11.18704.18Grahamox8 Graham405.204.05.26 Ivanowntity // View pull request (today 16:12)386 G38839239340941141341s417419420)421423)RecordSelector.php© Activity.php© Team,phpE IaravellogA HSJJocal (jiminny@localhost]A console (STAGING]# СОЛЬОС PHUA console (EU] x ( users (EU)Cascadeles Orcnnworeebeeionhmwesotino ooroThc AutoORDER BY t.name, u.email;• git show c6038d8a29 - app/Services/Crm/Hubspot/Service-phpconnit c6838d8a29357787e8ac3c46916b88a8dSd8080eclass Service extends BaseService inplementspublic function importstages(?array Stypes = null, ?string SnissingStageNane = null): ?Stage170601 47 A149 X1 233 21 A V 1707-17081709paassarstde a nultn171017111712try t1713// Use the HubSpot API client instead of the SDK crmPipelines() nethodSendpoint = self::getDealsPipelinesEndpoint);1715SpipelinesResponse = Sthis->client->getInstance()->getClient()-›request( method:) 'GET', Sen1716sozpebines = sozpetzneskesponse->daca->resutcs-1717j catch (RequestException|BadRequest Sexception) (-1718throw sexcep zonSe jiminny~031 49 A29 X3 X109 A VJY-20197 return deleted inportd1f1 --git s/app/Services/Crm/Hubspot/Service.php b/app/Services/Cra/Hubspot/Service.php=1720foreach (Spipelines as Spipeline) €Sp = ResponseNornalize: :normalizePipeline(Spipeline);// Create/update business process for this pipelinehusinessprocessnhisosconachusness?rocesses oundaretrerearerdiern_provider_id' = Sp['id'].1, ttean_id*"name"Sthis->tean->id,nhotrsmodthiSorlabelestart: 8,"type"is_selectable'=> BusinessProcess:: TYPE_OPPORTUNITY,»> $p['active'].1 A recerd type ie reatly a elene of the bushes prosess, uste to stere mtich resond vaim// Create/update record type cloneSthis->config->recordTypes()->update0rCreateCI'crn_provider_id' => $p['id'],1. G"tean_id"→> Sthis->team->id,=> mb_strimwidth(Sp('Label'), (start 0, (width: 150),"is_selectable'=> $pl'active'),"business_process_id' => $businessProcess->id 27 null,D):1.7261728=1729=173€1731E1732-1733=1755E17391740=1742—1742=1743=1744=17451746 2=1748SELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SELECTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-u.enail,sa.x,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce':• qit show 87146179ba - app/Services/Crn/Hubspot/Service.php=select * fron activities where id = 31264367:select * fron contacts where id = 6331639;select * fron accounts where id = 4156632;select * fron opportunities where id = 4843610;# updateacove0c0un8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-0S-22 07:16:58 12:22:56 2e25 vezove) Jminny- Com»Sune ttosooreowe benksot/Service-php b/app/Services/Crm/Hubspot/Service.phpNow let me look at the Nov 2075 bulk imoort = whatetnoor Stages looked like at that time.select * fron text_relays where created_at > '2026-05-01':Command git, headselect * fron actvales order oy 1d descaselect * fron users where nane oikesubrasalloo wneun —orwo-ire-i9ad00/ervcse/htoscowerce.ohone.d=560720d53 2 0618 Ated Be e Liiat o -ubseo Tohe o EVent by plagete a recordhandle proper not found exceptionsI retry on unexpected exceptsonsSELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:lhenasa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id= sa.sociable_idJOIN teans t 1.n<->1: on t.id = u.tean.idWHERE u.tean_id = 100 and sa.provider = "hubspet":© git show 874c3cea56 - app/Services/Crm/Hubspot/Service-php | grep -A 40 "inportStages"© at chou StctzetdSbanoo/Senyiices/Cm/Mubsoot/Seryiicoroho aren cA Sa "tunct ion simoortStaoee"public function inportStages(tarray Stypes = null, Zstring SmissingStageNane = nutl): 7Stagekgimsinee nuiadtry i use the HubSpot API client instead of the SOK cmnPipelines() nethodselect id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 5SS and stage_id = 28616 order_*select id, crn_provider_id, nane, probability, updated_at, deletedefron stageswhere id = 28616;// Stages - fetch all existing stages upfront to avoid N+1 querieses= sthisescont toosstages on-wwithTrashedO)-›ahere('type', Stage:: TYPE_OPPORTUNITY)Ask anything (XOL)11!ceodh• OKwweuname2 4 space...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88379
|
|
88378
|
Project: faVsco.js, menu
HomeDMsActivityFilesLater Project: faVsco.js, menu
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:00:278 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88378
|
|
88377
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
rapstomEV faVsco,ls ~ProjectvCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPono© SyncFieidAction.phpCSWnCKealCohewW© WebhookSyncBatchProcelisteners> MetadataMigrationP oedriveSalesforceafeldsOpportunityMatcherOpportunitySyncStrategyProspectSearchStrategy© Cient.php© DecorateActivity.phpG DeleteObjectsTrait.phpoewanarinithooe nha© PayloadBuilder.php© Profile.php©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.php© SyncBatchRedisService.ptTraits© BaseCllent.phpCwastemoeene© CachedCrmServiceDecoratorCrmactivity ProviderintegrateCCWCMWMoron©rmobiectsteso wer.ono© DefaultProspectSearchStrateC Emal telcerond3Findeproscectinterace.onoC) LavouMansoe onoC Opportun tvActvitwlatcheeennortur wewn.CtestomedProspectCache.php(C ProspectSearchScope.phpWindowexisiinastaadLu.Ulco ropozo19.03.18 Graham2.04.18Graham24.04.18 Graham24.04.lo Olanidn3.10.253.10.2513.10.25 Nikolov13.10.25 Nikolov10.09.25 ma24.04.18 Graham24.04.18 Graham19.03.18 Graham704.18Graham19.03.18 GrahamGrahan3.10.25onowcraham2.10.2517.03.25 lllan16.04.25 Ivanov710252.04.183.10.25Graham2.04.18Graham19.03.18 Graham2.04.18Graham20.10.21 Graham2.10.252.04.18Graham16.04.25 Ivanow2.10.258.11.18704.18Grahamox8 Graham405.204.05.26 Ivanowntity // View pull request (today 16:12)386 G38839239340941141341s417419420)421423)TO0У L7Thu 28 May 20:00:26U ServiceTest ~RecordSelector.php© Activity.php© Team,phpE IaravelJogA HSJJocal (jiminny@localhost]A console (STAGING]# СОЛЬОС PHUA console (EU] x E users (EU)Thc AutoORDER BY t.nane, u.email;Cascadeles Orcnnworeebeeionhomwstotino ooso+0.mo learitat lon foroccetsvene pron aP Cene oue Satesfore c ueanes up Tros all uens out satestorceaccounts to batch job & change sync approachclass Service extends BaseService inplementspublic function importstages(?array Stypes = null, ?string SnissingStageNane = null): ?Stage170601 47 A149 X1 233 21 A V 1707-1708170917101711Se jiminny~031 49 A29 X3 X109 A Vngge spoce Linter fixSELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.paassarstde a nultntry t1713// Use the HubSpot API client instead of the SDK crmPipelines() nethodSendpoint = self::getDealsPipelinesEndpoint);1715SpipelinesResponse = Sthis->client->getInstance()->getClient()-›request( method:) 'GET', Sensozpebznes = sozpetzneskesponse->daca->resutcs-1717j catch (RequestException|BadRequest Sexception) (-1718throw sexcep zon=1720foreach (Spipelines as Spipeline) €Sp = ResponseNornalize: :normalizePipeline(Spipeline);// Create/update business process for this pipelinehusinessprocessnhisosconachusness?rocesses oundaretrerearerdiern_provider_id' = Sp['id'].1, ttean_id*"name""type"is_selectable'Sthis->tean->id,nhotrsmodthisorhabel"nstart: 8,=> BusinessProcess:: TYPE_OPPORTUNITY,»> $p['active'].he 459117261728=172917301731E1732-1733=1735=17361737Il A record type is really a clone of the bu// Create/update record type cloneSthis->config->recordTypes()->update0rCreate'crn_provider_id' => $p['id'],1. G© ExtendedHasManypublic function updateurcreatelray Svatues e05): nulz"tean_id"→> Sthis->team->id,=> mb_strimwidth(s"is_selectable'=> $pl'active'),ousinessprocess1d = Sousznessprocescreate or update a related recoro matchine dnenttributae aod Flit wih walad$17351740Ea7421742-1743E1744-1745174611747-1748SEEiNTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-u.enail,sa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce":• gít shơw c683808a29 - app/Services/Cra/Hubspot/Service.phpt Fe 27 16:87318 2826 4020311. consJY-20197 return deleted inportd1ff --git з/app/Services/Cra/Hubspot/Service.php b/app/Services/Crm/Hubspot/Service.phpselect * fron activities nhere id = 31264367:select * fron contacts where id = 6331639;select * fron accounts where id = 4156632;select * fron opportunities where id = 4843610;#Uodare300n8-4300-4"contact_id' = 6."updated_at' = 2026-0S-22 07:16:Command ci• qft show 8714617963 - a00/Services/Cra/Hubspot/Servitce.oheselect * fron text_relays where created_at > '2026-05-01':select * fron actvales order oy 1d desca5e 12222:56 2y veove/ iainny. comvne HTosoor tNe eneJindex al8t 3c008/523515e6/31 1006spsot/Service.php b/app/Services/Crm/Hubspot/Service.phpIIlselect * fron users where nane uike subras:Now let me lock at the Noy 2025 buimoor - whateinoortStages looked ike at that timesSELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE*sa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idahiittinneneesdneettessWHERE u.tean_id = 100 and sa.provider = 'hubsRes":eaod conean coctor ualot" ceiiter7u,-i9e ae noo serienleritoseor SereohahendBE961e Nted se ettat o ueekt Tohe or eVenl agate recore• git show 874c3cea56 — app/Services/Cra/Hubspot/Service-php | grep -A 40 "InportStages"D):select id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 5SS and stage_id = 28616 order_*select id, crn_provider_id, nane, probability, updated_at, deleterefron stageswhere id = 28616;0 git show 5td7281d5b:app/Services/Crn/Hubspot/Service-php | grep -A 50 "function inportStages"// Stages - fetch all existing stages upfroneg= sthisescont lac›stagesol-wwithTrashedo)-›ahere('type', Stage:: TYPE_OPPORTUNITY)Ask anything (XOL)HrestiuntsemceeteiwCioudCall/ServiceTest.phpceodhAdhet• OKwweuname2 4 space...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88377
|
|
88376
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
1
7
rapstomEV faVsco,ls ~ProjectvCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPono© SyncFieidAction.phpCSWnCKealCohewW© WebhookSyncBatchProcelisteners> MetadataMigrationP oedriveSalesforceafeldsOpportunityMatcherOpportunitySyncStrategyProspectSearchStrategy© Cient.php© DecorateActivity.phpG DeleteObjectsTrait.phpoewanarinithooe nha© PayloadBuilder.php© Profile.php©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.php© SyncBatchRedisService.ptTraits© BaseCllent.php© CachedCrmServiceDecoratorCrmactivity ProviderintegrateCCWCMWMoron©rmobiectsteso wer.ono© DefaultProspectSearchStrateC mallteloer.ond3Findeproscectinterace.onoC) LavouMansoe onoC Opportun tvActvitwlatcheeennortur wewn.CtestomedProspectCache.php(C ProspectSearchScope.phplWindowexisiinastaadLu.Ulco ropozo19.03.18 Graham2.04.18Graham24.04.18 Graham24.04.lo Olanidn3.10.253.10.2513.10.25 Nikolov13.10.25 Nikolov10.09.25 ma24.04.18 Graham24.04.18 Graham19.03.18 Graham704.18Graham19.03.18 GrahamGrahan3.10.25onowcraham2.10.2517.03.25 llian16.04.25 Ivanov710252.04.183.10.25Graham2.04.18Graham19.03.18 Graham2.04.18Graham20.10.21 Graham2.10.252.04.18Graham16.04.25 Ivanow2.10.258.11.18704.18Grahamox8 Graham405.204.05.26 Ivanowntity // View pull request (today 16:12)386 G38839239340941141341s417419420)421423)TO0У L7Thu 28 May 20:00:23U ServiceTest ~RecordSelector.php© Activity.php© Team,phpE IaravellogA HSJJocal (jiminny@localhost]A console (STAGING]# ConbocrhouA console (EU] x E users (EU)Cascadeles Orcnnworeeoeionhwmwlino ooo+0.Thc AutoORDER BY t.name, u.email;class Service extends BaseService inplementspublic function importstages(?array Stypes = null, ?string SnissingStageNane = null): ?Stage170601 47 A149 X1 233 21 A V 1707-17081709paassarstde a nultn171017111712try t1713// Use the HubSpot API client instead of the SDK crmPipelines() nethod1714Sendpoint = self::getDealsPipelinesEndpoint);1715SpipelinesResponse = Sthis->client->getInstance()->getClient()-›request( method:) 'GET', Sen1716sozpebznes = sozpetzneskesponse->daca->resutcs-1717j catch (RequestException|BadRequest Sexception) (-1718throw sexcep zonSe jiminny~031 49 A29 X3 X109 A V• git log —oneline -aftera"2025-10-01" -beforew"2026-04-29" - app/Services/Cra/Hubspot/Service-phpBe38236 ron thet hoadatonyortBu , nes roeti 90. oe 3 0r tRlysio A roretyo5,are cleancd up trom all crys but Salestorce=1720foreach (Spipelines as Spipeline) €Sp = ResponseNornalize: :normalizePipeline(Spipeline);// Create/update business process for this pipelinehustnessprocessnhisoscontaghusiness?rocesses osundaretneneare oiern_provider_id' = Spl'id'1.1, ttean_id*"name"Sthis->tean->id,nhotrsmodthisorhabel"nstart: 8,"type"is_selectable'=> BusinessProcess:: TYPE_OPPORTUNITY,»> $p['active'].1 A recerd type ie reatly a elene of the bushes prosess, uste to stere mtich resond vaim// Create/update record type cloneSthis->config->recordTypes()->update0rCreateCI'crn_provider_id' => $p['id'],1. G"tean_id"→> Sthis->team->id,=> mb_strimwidth(Sp('Label'), (start 0, (width: 150),'is_selectable'=> $pl'active'),"business_process_id' => $businessProcess->id 27 null,1.7261728=1729=173€1731E1732-1733=1755E17391740=1742—1742=1743=1744=17451746 2=174811!SELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SELECTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-u.enail,sa.x,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce':P id tis eo t te• qit show c603808a29 - app/Services/Crn/Hubspot/Service.phpselect * fron activities where id = 31264367:select * fron contacts where id = 6331639;select * fron accounts where id = 4156632;select * fron opportunities where id = 4843610;# updateacove0c0un8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-0S-22 07:16:x-8208a1l. com-yowereumoelessteoorindex 7456 3/S03/52735/2 180650sot/Service.php b/app/Services/Crm/Hubspot/Service.php--- a/app/Services/Crm/Hubspot/Service.phpselect * fron text_relays where created_at > '2026-05-01':ai chon 8114.17969 = a00/Senyiices/cr//Mubsoot/Service.ohdselect * fron actvales order oy 1d descaselect * fron users where nane oikesubrasSync Hubspot Active Dealsindex Bi8bo3(828/53715-31 18ebspot/Service php b/Ap/Services/Crm/Hubspot/Service.php100644SELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:lhenasa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id= sa.sociable_idJOIN teans t 1.n<->1: on t.id = u.tean.idWHERE u.tean_id = 100 and sa.provider = "hubspet":Now let me look at the Nov 2025 bulk import — what importStages looked like at that time:• git log —oneline —before="2025-11-19" —after="2025-09-01" - app/Services/Cra/Hubspot/Service.php | head -55td728fd5bor Event oy olayboo272464f180 JY-19613 / retry on unexpected exceptionsD):select id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crt© ait chou 8142cc56 e noo/Serutces/Cr//Mubsnot/Serviceaoho ll arco =A 40 "inoortStageefron opportunities where tean_id = 5SS and stage_id = 28616 order_*select id, crn_provider_id, nane, probability, updated_at, deletedefron stageswhere id = 28616;// Stages - fetch all existing stages upfront to avoid N+1 querieseg= sthisescont lac›stagesol-wwithTrashedO)-›ahere('type', Stage:: TYPE_OPPORTUNITY)Ask anything (XOL)ceodh• OKwweuname2 4 spac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88376
|
|
88375
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Code changed:
Hide
Sync Changes
Hide This Notification
1
7
149
rapstomEV faVsco,ls ~ProjectvViewCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPonoexistinastaad© SyncFieidAction.php10.02.23 Vasilev© synckelateoncuvnywanas 20.07.23 toni-yminny© WebhookSyncBatchProce20.07.23 toni-jiminny20.07.23 toni-fiminnylisteners20.07.23 toni-jiminny> Metadata20.07.23 toni-fiminnyMigration30.09.24 PapazovP oedrive20.07.23 toni-jiminnySalesforce19.03.18 Grahamafelds19.03.18 GrahamOpportunityMatcher9.05.18OpportunitySyncStrategyGrahamProspectSearchStrategy19.03.18 GrahamUl taoro19.03.18 Graham© Cient.php2.04.18Olahan© DecorateActivity.php24.04.18 GrahamG DeleteObjectsTrait.phpewero oranat©FieldDefinitions.php© PayloadBuilder.php3.10.25© Profile.php3.10.25©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.phpKHOS NIKOO10.09.25 ilian74.04.18 Graham24.04.18 Graham9oxh8 Graham© SyncBatchRedisService.ptTraits© BaseCllent.phpcrahem19.03.18 Graham© BaseService.php© CachedCrmServiceDecorator2.10.25© CrmActivityProviderintegrateCCWCMWMoronCermcontcurationsettinosse2.10.25©rmobiectsteso wer.ono17.03.25 ilian© DefaultProspectSearchStrate16.04.25 IvanovC Emal telcerond2.10.25Nikolov3sindeProscectinternce.ono2.04.18GrahamC) LavouMansoe ono® MatchDomainByEmailinterfac 2.04.18GrahamC Opportun tvActvitwlatcheee19.03.18 Graham® OpportunitySyncStrategyinte2.04.18Canateennortur wewn.CtestomedProspectCache.php20.10.21 GrahamHe OrnenontCostrhSrond nhnentity // View pull request (today 16:12)WindowTO0У L7Thu 28 May 20:00:20U ServiceTest ~© DeleteObjects Trait.phpuorcoaiuocrd.pntRecordSelector.php© Activity.php© Team,php© HubspotLastModifiedCreatedRecentlyOpenSyncStrategy.phpE custom.logE laravellogA HSJJocal (jiminny@localhost]A console (STAGING]# СОЛЬОС PHUCascadeA console (EU] x E users (EU)les Orcnnworeebeeionhomwwtino oooo+0.Clost oias no seiveironx5 Cc334 C336337382384386 €389407409421413)415class Service extends BaseService inplements* Bcetucn EieldDatal]170601 47 A149 X1 233 21 A v 1707-17081709public function inportPicklistValues(17101711Eleld Sfield,1114array Soptions = [l'id''Label' »> "*, "value' »> **]].): array {..)-1717-1718public function inportStages(?array $types = null, Pstring SaissingStageNane = null): ?Stage-1728=1720whesoernorTITE// Use the HubSpot API client instead of the SDK crnPipelines() nethodsendooint= selt..oerten.sproeanesandoo.nroSpipelinesResponse = Sthis-›client->getInstance() ->getClient() -request( method:) "GET'.Soioeiaines a sotoeluneskesponse-›data-›resu.ts} catch (RequestException|BadRequest Sexception) ({1726=1729=1730foreach (Spipelines as Spipeline) €NstaceseeE7sa-1733// We create a business process to contain the pipeline, and store all stages against=1735Sp = ResponseNornalize::nermalizeP$peline(Spipeline);1736-1737// Create/update business process for this pipelineSbusinessProcess = Sthis->config->businessProcesses()->update0rCreateCC'ern_provider_id' => $p['id'],1. E"tean_id'"name'ype-1738E17391740=1742=> Sthis->team->id,=> mb_strimwidth(Sp('Label'), (start: 0, (width: 150),=> BusinessProcess:: TYPE_OPPORTUNITY,=> $p['active').—1742=1743=1744=1745D):I1 A record type is really a clone of the business process, used to store nhich recond ves 1748.// Create/update record type cloneSthis->config->recordTypes()->update0rCreate(t'crn_provider_id' => Spl'id'],111Thc AutoORDER BY t.nane, u.email;Se jiminny~031 49 A29 X3 X109 A V• git log —oneline —after="2825-18-01" —before="2026-04-20" — app/Services/Cr/Hubspot/Service-phpSELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SEEiNTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-Mrenasisa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce':• git shơw c6838d8a29 -- app/Services/Crn/Hubspot/Service-php=select * fron activities nhere id = 31264367:select * fron contacts where id = 6331639;aeleck x tron accoun ancht o-450054select * fron opportunities where id = 4843610;#Uodare0c0un8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-0S-22 07:16:716: 87313 2826 10283 11. comJY-20197 return deleted importd1f1 -gtt a/app/Services/Cra/tubspot/Service.php b/app/Services/Crm/Hubspot/Service.phpselect * fron text_relays where created_at > '2026-05-01':• git show 87146179ba — app/Services/Cra/Hubspot/Service-phpselect * fron actviates order oy 1d desc;select * fron users where nane uike subras:index 8i8t9 3C008/S13775e8/31 18u5spot/Service-php b/app/Services/Cra/Hubspot/Service.phpSELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTMesansa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubsRes":Now let me look at the Nov 2025 bulk import - what inportStages looked like at that time:CONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:• git log -oneline -beforer"2825-11-19" -after="2025-09-01" - app/Services/Crn/Hubspot/Service-php | head -s560728e85b 2Y-18618 tted stve tagatat Tor -cheekt tohk or Events oy layare,proper not found exceptions2724b4f180 JY-196136xselect id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 555 and stage_id = 20616 order]select id, crn_provider_id, nane, probability, updated_at, deleterefron stageswhere id = 28616;0 git show 874c3ceaS6 - app/Services/Crn/Hubspot/Service-php | grep -A 40 "inportStages"(Run 33-) (SkipAsk anything (XOL)Adhet• OKtwodeurlhtmeshires2 4 spac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88375
|
|
88374
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:00:208 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88374
|
|
88373
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
existingStages
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/2
rapstomEV faVsco,ls ~ProjectvViewCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPonoexisiinastaad© SyncFieidAction.php10.02.23 Vasilev© synckelateoncuvnywanas 20.07.23 toni-yminny© WebhookSyncBatchProce20.07.23 toni-jiminny20.07.23 toni-fiminnylisteners20.07.23 toni-jiminny> Metadata20.07.23 toni-fiminnyMigration30.09.24 PapazovP oedrive20.07.23 toni-jiminnySalesforce19.03.18 Grahamaleelds19.03.18 GrahamOpportunityMatcher9.05.18OpportunitySyncStrategyGrahamProspectSearchStrategy19.03.18 GrahamUl taoro19.03.18 Graham© Cient.php2.04.18Olahan© DecorateActivity.php24.04.18 GrahamG DeleteObjectsTrait.phpewero oranat©FieldDefinitions.php© PayloadBuilder.php3.10.25© Profile.php3.10.25©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.phpKHOS NIKOO10.09.25 ilian74.04.18 Graham24.04.18 Graham9oxh8 Graham© SyncBatchRedisService.ptTraits© BaseCllent.phpcrahem19.03.18 Graham© BaseService.php© CachedCrmServiceDecorator2.10.25© CrmActivityProviderintegrateCCWCMWMoronCermcontcurationsettinosse2.10.25©rmobiectsteso wer.ono17.03.25 flian© DefaultProspectSearchStrate16.04.25 IvanovC mallteloer.ond2.10.25Nikolov3sindeProscectinternce.ono2.04.18GrahamC) LavouMansoe ono® MatchDomainByEmailinterfac 2.04.18GrahamC Opportun tvActvitwlatcheee19.03.18 Graham® OpportunitySyncStrategyinte2.04.18Canateennortur wewn.CtestomedProspectCache.php20.10.21 GrahamHe OrnenontCostrhSrond nhnentity // View pull request (today 16:12)WindowU ServiceTest ~TO0У L7Thu 28 May 20:00:15+0.© DeleteObjects Trait.phpuorcoaiuocrd.pntRecordSelector.php© Activity.php© Team,php© HubspotLastModifiedCreatedRecentlyOpenSyncStrategy.phpE custom.logE laravellogA HSJJocal (jiminny@localhost]A console (STAGING]# СОЛЬОС PHUA console (EU] x ( users (EU)Clost oias no seiveironx5 Cc334 C336337382384386 €389407409421413)415class Service extends BaseService inplements* Bcetucn EieldDatal]170601 47 A149 X1 233 21 A v 1707-17081709public function inportPicklistValues(17101711Eleld Sfield,1114array Soptions = [l'id''Label' »> "*, "value' »> **]].): array {..)public function inportStages(Parray $types = null, Pstring SaissingStageNane = null): ?Stagewhesoernor// Use the HubSpot API client instead of the SDK crmPipelines() nethodsendooint a selt..oerten.sproeanesandoonroSpipelinesResponse = Sthis-›client->getInstance() ->getClient() -request( method:) "GET'.Soioeiaines a sotoeluneskesponse-›data-›resu.ts} catch (RequestException|BadRequest Sexception) (-1717-1718-1728=1720TITE{1726=1729=1730foreach (Spipelines as Spipeline) €NstaceseeE7sa-1733SELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMT// We create a business process to contain the pipeline, and store all stages againstSp = ResponseNornalize::nermalizeP$peline(Spipeline);=1735CONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE:1736-1737// Create/update business process for this pipelineSbusinessProcess = Sthis->config->businessProcesses()->update0rCreateCC-1738'ern_provider_id' => $p['id'],E17391. E1740sa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubsRes":=1742"tean_id'"name'=> Sthis->team->id,—1742select id, is_closed, is_won, stage_updated_at, crm_provider_id, st=> mb_strimwidth(Sp('Label'), (start: 0, (width: 150),=1743ype=> BusinessProcess:: TYPE_OPPORTUNITY,=1744close_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 555 and stage_id = 20616 order]D):=> $p['active').=1745select id, crn_provider_id, nane, probability, updated_at, deletereI1 A record type is really a clone of the business process, used to store nhich recond ves 1748.fron stageswhere id = 28616;// Create/update record type cloneSthis->config->recordTypes()->update0rCreate(t'crn_provider_id' => Spl'id'],111Thc AutoORDER BY t.nane, u.email;Se jiminny~031 A9 A29 V3 /109 A VSELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SEEiNTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-Mrenasisa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce':select * fron activities nhere id = 31264367:select * fron contacts where id = 6331639;aeleck x tron accoun ancht o-450054select * fron opportunities where id = 4843610;#Uodare0c0un8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-0S-22 07:16:select * fron text_relays where created_at > '2026-05-01':select * fron actviates order oy 1d desc;select * fron users where nane uike subras:Cascadeles orceeneeworceoeionhomwso1ino ooeod1t1 -git 3/agp/Services/Crm/Hubspot/Service.php b/app/Services/Cr/Hubspot/Service.phoicesCcemtubspot/Service. phpat loo =onelne atten75=80 betores"2026-84-28" a a00/Services/cre//Hubspot//Service.oho8828537871 Drop the pandatory dunny inplemntation of ImportBusinessProcesses.all cers out Solesforee cleaned up fron all CRMs but Salesforce.and moor accounts to ostch 1o0 a chande sune doonosoaddress code reviem suggestions6513061818 5ixgg yp0ce Linter fix.• git show c6838d3a29 - app/Services/Crn/Hubspot/Service.phpAuthor:Date:Fri Feb 27 16:87:18 2826 +0280JY-20197 return deleted inportdAtex 74563/03/Serv3s/e2140b-hesspot/service-pap b/app/servaces/cra/hubspot/service-php- а/aрр/Services/Crm/Hubspot/Service.phpCommand o• qit show 87146179ba - app/Services/Crn/Hubspot/Service.pheSune ttosoorowe aentwowlemelooicarthewwtirswmoor=wharssoortsaans.lloskecllke.arthat..ime•git log —oneline —before="2025-11-19" —-after="2025-09-01"- a00/Seryices/ere//Huosoor/Saryce.ohohesd =sAsk anything (XOL)ceodhAdhet• OXwodeurlhime"eshires2 4 spac...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88373
|
|
88372
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
rapstomEV faVsco,ls ~ProjectvViewCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPonoexisiinastaad© SyncFieidAction.php10.02.23 Vasilev© synckelateoncuvnywanas 20.07.23 toni-y minny© WebhookSyncBatchProce20.07.23 toni-jiminny20.07.23 toni-fiminnylisteners20.07.23 toni-jiminny> Metadata20.07.23 toni-fiminnyMigration30.09.24 PapazovP oedrive20.07.23 toni-jiminnySalesforce19.03.18 Grahamafelds19.03.18 GrahamOpportunityMatcher9.05.18OpportunitySyncStrategyGrahamProspectSearchStrategy19.03.18 GrahamUl taoro19.03.18 Graham© Cient.php2.04.18Olahan© DecorateActivity.php24.04.18 GrahamG DeleteObjectsTrait.phpewero oranat©FieldDefinitions.php© PayloadBuilder.php3.10.25© Profile.php3.10.25©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.phpKHOS NIKOO10.09.25 ilian74.04.18 Graham24.04.18 Graham9oxh8 Graham© SyncBatchRedisService.ptTraits© BaseCllent.phpcrahem19.03.18 Graham© BaseService.php© CachedCrmServiceDecorator2.10.25© CrmActivityProviderintegrateCCWCMWMoronCermcontcurationsettinosse2.10.25©rmobiectsteso wer.ono17.03.25 ilian© DefaultProspectSearchStrate16.04.25 IvanovC Emal telcerond2.10.25Nikolov3Findeproscectinterace.ono2.04.18GrahamC) LvoutMansoeono® MatchDomainByEmailinterfac 2.04.18GrahamC Opportun tvActvitwlatcheee19.03.18 Graham® OpportunitySyncStrategyinte2.04.18Citanaiteennortur wewn.CtestomedProspectCache.php20.10.21 GrahamHe OrnenontCostrhSrond nhnentity // View pull request (today 16:12)WindowU ServiceTest ~TO0У L7Thu 28 May 20:00:12+0.© DeleteObjects Trait.phpuorcoaiuocrd.pntRecordSelector.php© Activity.php© Team,php© HubspotLastModifiedCreatedRecentlyOpenSyncStrategy.phpE custom.logE IaravelJogA HSJJocal (jiminny@localhost]A console (STAGING]# СОЛЬОС PHUA console (EU] x E users (EU)Cascadeles Orcnnworeebeeionhomwstotino oosoClost oias no seiveironx5 Cc336337382384386 €389407409421413)415class Service extends BaseService inplements* Bcetucn EieldDatal]170601 47 A149 X1 233 21 A v 1707-17081709public function inportPicklistValuesC17101711Eleld Sfield,1114array Soptions = [l'id''Label' »> "*, "value' »> **]1.): array {..)-1717-1718public function inportStages(Parray $types = null, Pstring SaissingStageNane = null): ?Stage-1728=1720Dnesoer norkTITE// Use the HubSpot API client instead of the SDK crnPipelines() nethodsendooint a selt..oerlealsproeanesandooinroSpipelinesResponse = Sthis-›client->getInstance() ->getClient() -request( method:) "GET'.Soioeiuines & soloeld neskesponse-›data-results} catch (RequestException|BadRequest Sexception) ({1726=1729=1730foreach (Spipelines as Spipeline) €NstaceseeE7sa-1733// We create a business process to contain the pipeline, and store all stages against=1735Sp = ResponseNornalize::nermalizeP$peline(Spipeline);1736-1737// Create/update business process for this pipelineSbusinessProcess = Sthis->config->businessProcesses()->update0rCreateCC'ern_provider_id' => $p['id'],1. E"tean_id'"name'ype-1738E17391740=1742=> Sthis->team->id,=> mb_strimwidth(Sp('Label'), (start: 0, (width: 150),=> BusinessProcess:: TYPE_OPPORTUNITY,=> $p['active').—1742=1743=1744=1745D):I1 A record type is really a clone of the business process, used to store nhich recond ves 1748.// Create/update record type cloneSthis->config->recordTypes()->update0rCreate(t'crn_provider_id' => Spl'id'],111Thc AutoORDER BY t.nane, u.email;Se jiminny~031 A9 A29 V3 /109 A VSELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.Món Day 1 12:19:47 2026 18306Jy-20807 Restore loise, a / en eatesenrte.anp b/sp/.sertces/crm/esot/Sserte,.psSEEiNTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-Mrenasisa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce':• git 1og-oneline —after="2025-10-01" —before="2826-04-20" -- app/Services/Crm/Hubspot/Service.phpanpleantacion or tnoortbusinessprocessesi- are cleaned up fron all CRMs but Salesforceinport contacts and import accounts to batch job & change sync approachY-28197 address code review suggestionsselect * fron activities nhere id = 31264367:select * fron contacts where id = 6331639;Belecekx tron accoun ancheo- 450054select * fron opportunities where id = 4843610;#Uodare0c0un8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-0S-22 07:16:• qft show <693849a29 - apo/Services/Crm/Hubspot/Service.ohrkag2gma11. comselect * fron text_relays where created_at > '2026-05-01':select * fron actviates order oy 1d desc;dndex 7436 3/308/52092735/2 105spsot/Service.php b/app/Services/Crm/Hubspot/Service.phpselect * fron users where nane tuike "subraaSELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where 1d= 555%select * fron stages where tean_id = 555;SETSTMTCONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN" (owner)" ELSEMesansa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubsRes":• git show 87146179ba - app/Services/Crn/Hubspot/Service-phpSync Hubspot Active Dealsindex 0l80 3628/S1371546451 /8ubspot/Service.php b/App/Services/Cra/Hubspot/Service. phpNow let me look at the Nov 2025 bulk import - what inportStages looked like at that time:Command cin nasoselect id, is_closed, is_won, stage_updated_at, crm_provider_id, stclose_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = 555 and stage_id = 20616 order]select id, crn_provider_id, nane, probability, updated_at, deleterefron stageswhere id = 28616;O git log -oneline —before="2825-11-19" --after="2025-09-01" -- app/Services/Crm/Hubspot/Service.php| head -sRun se+ (SkipAsk anything (XOL)AdhetKwweuname• O2 4 spao...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88372
|
|
88371
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:00:128 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88371
|
|
88370
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
ServiceTest
Run 'ServiceTest'
Debug 'ServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Show Replace Field
Search History
rapstomEV favscojs ~ProjectvViewCooc#12121 on JY-20963-fix-InHubspotClientinterface.ph© HubspotTokenManager.pt© PayloadBuilder.phpoKimol Cimosewhoo© ResponseNormalize.phpCSeMCPonoexisiinastaad© SyncFieidAction.php10.02.23 Vasilev© synckelateoncuvnywanas 20.07.23 toni-y minny© WebhookSyncBatchProce20.07.23 toni-jiminny20.07.23 toni-fiminnylisteners20.07.23 toni-jiminny> Metadata20.07.23 toni-fiminnyMigration30.09.24 PapazovP oedrive20.07.23 toni-jiminnySalesforce19.03.18 Grahamaleelds19.03.18 GrahamOpportunityMatcher9.05.18OpportunitySyncStrategyGrahamProspectSearchStrategy19.03.18 GrahamUl taoro19.03.18 Graham© Cient.php2.04.18Olahan© DecorateActivity.php24.04.18 GrahamG DeleteObjectsTrait.phpewero oranat©FieldDefinitions.php© PayloadBuilder.php3.10.25© Profile.php3.10.25©QueryBullder.php©QueryHandler.php©Querylterator.php©QueryResults.php© Service.phpKHOS NIKOO10.09.25 ilian74.04.18 Graham24.04.18 Graham9oxh8 Graham© SyncBatchRedisService.ptTraits© BaseCllent.phpcrahem19.03.18 Graham© BaseService.php© CachedCrmServiceDecorator2.10.25© CrmActivityProviderintegrateCCWCMWMoronCermconticurationSettinass2.10.25©rmobiectsteso wer.ono17.03.25 ilian© DefaultProspectSearchStrate16.04.25 IvanovC mallteloer.ond2.10.25Nikolov3Findeproscectinterace.ono2.04.18GrahamC) LvoutMansoeono® MatchDomainByEmailinterfac 2.04.18GrahamC Opportun tvActvitwlatcheee19.03.18 Graham® OpportunitySyncStrategyinte2.04.18Canateennortur wewn.CtestomedProspectCache.php20.10.21 GrahamHe OrnenontCostrhSrond nhnentity // View pull request (today 16:12)Window© DeleteObjects Trait.phpuorcoaiuocrd.pntRecordSelector.php© Activity.php© Team,php© HubspotLastModifiedCreatedRecentlyOpenSyncStrategy.phpE custom.logE IaravelJogA HSJJocal (jiminny@localhost]A console (STAGING]# СОЛЬОС PHUA console (EU] x ( users (EU)Clost oias no seiveironThc AutoORDER BY t.name, u.email;Se jiminny~031 A9 A29 V3 /109 A Vx5 Cc336337382384386 €389407409421413)415class Service extends BaseService inplements* Bcetucn EieldDatal]170601 47 A149 X1 233 21 A v 1707-17081709public function inportPicklistValues(17101711Eleld Sfield,1114array Soptions = [l'id''Label' »> "*, "value' »> **]1.): array {..)public function inportStages(Parray $types = null, Pstring SaissingStageNane = null): ?Stagewhesoernor// Use the HubSpot API client instead of the SDK crmPipelines() nethodsendooint a selt..oertea.sproebnesandoonrorSpipelinesResponse = Sthis-›client->getInstance() ->getClient() -request( method:) "GET'.Soioeiaines a sotoeluneskesponse-›data-›resu.ts} catch (RequestException|BadRequest Sexception) (-1717-1718-1728=1720TITE{1726SELECT * FROM teans WHERE nane LIKE "XTourlane%'; # 187, 209, 8154.SEEiNTCONCAT(u.id, CASE WHEN u.id = t.ouner_id THEN ' (owner)' ELSE-Mrenasisa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idJOIN teans t 1.nc->1: on t.id = u.tean_idWHERE u.tean_id = 187 and sa.provider = 'salesforce':select * fron activities nhere id = 31264367:select * fron contacts where id = 6331639;aeleck x tron accoun ancht o-450054select * fron opportunities where id = 4843610;#Uodare0c0un8-4300-4"contact_id' = 6.#"stage_id' = 13273,"updated_at' = 2026-0S-22 07:16:select * fron text_relays where created_at > '2026-05-01':select * fron actvales order oy 1d descaselect * fron users where nane tuike "Subrasa=1729=1730foreach (Spipelines as Spipeline) €NstaceseeE7sa-1733SELECT * FROM opportunities HHERE wwid_to_bin('04a9cfad-2c87-4453-sselect * fron teans where d = 555%select * fron stages where tean_id = 555;SETSTMT// We create a business process to contain the pipeline, and store all stages againstSp = ResponseNornalize::nermalizeP$peline(Spipeline);=1735CONCAT(U.Ld, CASE WHEN U.1d = t.ouner_id THEN " (owner)" ELSE1736-1737// Create/update business process for this pipelineSbusinessProcess = Sthis->config->businessProcesses()->update0rCreateCC-1738'ern_provider_id' => $p['id'],E17391. E1740sa.*,t.ouner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idahittinnetneosonettsWHERE u.tean_id = 100 and sa.provider = 'hubsRes":=1742"tean_id'"name'=> Sthis->team->id,—1742select id, is_closed, is_won, stage_updated_at, crm_provider_id, st=> mb_strimwidth(Sp('Label'), (start: 0, (width: 150),=1743ype=> BusinessProcess:: TYPE_OPPORTUNITY,=1744close_date, forecast_category, deleted_at, created_at, renotely_crtfron opportunities where tean_id = SSS and stage_id = 28616 order_tD):=> $p['active').=17451746select id, crn.provider.id, nane, probability, updated.at, deleter!I1 A record type is really a clone of the business process, used to store nhich recond ves 1748.fron stageswhere id = 28616;// Create/update record type cloneSthis->config->recordTypes()->update0rCreate(t'crn_provider_id' => Spl'id'],111Cascadeles Orcnnworeeoeionhomwwtino ooooJY-20001 Update deletcd Staoes, restore in recreatedTO0У L7Thu 28 May 20:00:03U ServiceTest ~+0.The May 4 change only addcd withirashedl and the soft-delete restore logic. The prcbabstity line is unchangcd = it was ss Carobabity"*10before and after.Now let me lock at the commt betore this one to see what inportStages looked like oricinalivaPatsho nisdyedamoo/semces/crWiuhsooservice.oheconnit 312298d5bd62518248b6e7d8d416c6420d740d84thor: Min day 1 12019:27 2026- +e3now83 Sninny. CокрJY-20887 | Restore logdiff bgit 3/a0p/Services/Crm/Hubspot/Service.php b/app/Services/Crm/Hubspot/Service.phg•git log —oneline -afterw"2825-10-01" -beforem"2026-04-20" - app/Services/Cra/Hubspot/Service-phpDropy the thodsatorpo rttus hessprotessstage Tmand Bugportrecoratypes- are cleaned up tron all CPMs but Solesforce.but Sunes or batch job & change sync approschY-28197 return deleted importddress code review suggestionspartsho cottrt7ow300/Semtces/crW/iubsoor/seruce.ohdFri Feb 27 16:07:18 2826 +8208Yomor retut Caletesoor7456636388/520027356e2 18ebspot/Service. php b/app/Services/Cra/Hubspot/Service. phpB50019servtce.phgeommand ci0 git show 87146179ba - app/Services/Crm/Hubspot/Service-phpAsk anything (XOL)AdhetKowodeurTetmeRun xe (Skip• O2 4 spao...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88370
|
|
88369
|
Project: faVsco.js, menu
#12121 on JY-20963-fix-im Project: faVsco.js, menu
#12121 on JY-20963-fix-import-on-deleted-entity, menu
Start Listening for PHP Debug Connections
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 20:00:038 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88369
|
|
88368
|
Project: faVsco.js, menu
HomeDMsActivityFilesLater Project: faVsco.js, menu
HomeDMsActivityFilesLater..•More+Slack> 0(ah]FileEditViewGoHistoryJiminny ...* Starredplatform-backend-...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday& infosec_internal_all# infra-changes# infrastructure_dev# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...WindowHelpSearch: in:#platform-inner-teamX*à platform-inner-teamMessagesBookmarks0 Channel Overview7 RefinementsO Files< PinsP Retro Action ItemsChanges:Monday, May 4th ~• Do not requeue duplicatesjiminny/app May 4th Added by GitHubNikolay Ivanov 1:48 PMhttps://github.com/jiminny/app/pull/12041, фикс за импорта на стейджове (само при hubspot се оказа )но има още една грешка за тях, слагаме стейджове от една организация на другаи не мога да намеря никьде в кода защона еи има две организации които не могат да се изтрият заради товаVasil Vasilev 2:07 PMимаше проблем със мачването на стейджове от една организация на другазаради кеширане на pipelineldпреди горе долу 10тина дена го гледахмеNikolay Ivanov 2:07 PMтой още го иматози пьт при stageвиж ми PRVasil Vasilev 2:08 PMpipelineld бeшe default за едно 5-6 организации, и там се омазваше кешапонеже няма нито crm coniguration id, нито team id включено в кеша дето заминава в РЕДИСа, да, това е сьщотодобре де, аз защо си мисля, че фикс за тоя проблем вече замина на продNikolay Ivanov 2:10 PMMessage & platform-inner-team+100% <78 • Thu 28 May 19:59:53®8 10Untitled +...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
88368
|