diff --git a/addons/crm_iap_lead/__manifest__.py b/addons/crm_iap_lead/__manifest__.py
index fa61c3d83e4..93975ae8220 100644
--- a/addons/crm_iap_lead/__manifest__.py
+++ b/addons/crm_iap_lead/__manifest__.py
@@ -10,8 +10,17 @@
'data/crm.iap.lead.industry.csv',
'data/crm.iap.lead.role.csv',
'data/crm.iap.lead.seniority.csv',
+ 'data/crm.iap.lead.technology.csv',
'data/message_template.xml',
'data/crm_iap_lead_data.xml',
+ 'data/ir_sequence_data.xml',
'security/ir.model.access.csv',
+ 'views/crm_lead_view.xml',
+ 'views/crm_iap_lead_views.xml',
+ 'views/res_config_settings_views.xml',
+ 'views/crm_iap_lead_templates.xml',
],
+ 'qweb': [
+ 'static/src/xml/leads_tree_generate_leads_views.xml',
+ ]
}
diff --git a/addons/crm_iap_lead/data/crm.iap.lead.technology.csv b/addons/crm_iap_lead/data/crm.iap.lead.technology.csv
new file mode 100644
index 00000000000..6f978e64840
--- /dev/null
+++ b/addons/crm_iap_lead/data/crm.iap.lead.technology.csv
@@ -0,0 +1,348 @@
+id,name,tech_tag
+crm_iap_lead_technology_1,1&1 Hosting,1_and_1_hosting
+crm_iap_lead_technology_2,3d Cart,3d_cart
+crm_iap_lead_technology_3,Acquia,acquia
+crm_iap_lead_technology_4,Acquisio,acquisio
+crm_iap_lead_technology_5,Act On,act_on
+crm_iap_lead_technology_6,Action Network,action_network
+crm_iap_lead_technology_7,Active Demand,active_demand
+crm_iap_lead_technology_8,Activecampaign,activecampaign
+crm_iap_lead_technology_9,Add To Any,add_to_any
+crm_iap_lead_technology_10,Adform Advertiser,adform_advertiser
+crm_iap_lead_technology_11,Adobe Business Catalyst,adobe_business_catalyst
+crm_iap_lead_technology_12,Adobe Connect,adobe_connect
+crm_iap_lead_technology_13,Adobe Dynamic Tag Management,adobe_dynamic_tag_management
+crm_iap_lead_technology_14,Adobe Experience Manager,adobe_experience_manager
+crm_iap_lead_technology_15,AdRoll,adroll
+crm_iap_lead_technology_16,Airbrake,airbrake
+crm_iap_lead_technology_17,Akamai,akamai
+crm_iap_lead_technology_18,Akamai DNS,akamai_dns
+crm_iap_lead_technology_19,Alexa,alexa
+crm_iap_lead_technology_20,Altocloud,altocloud
+crm_iap_lead_technology_21,Amazon Associates,amazon_associates
+crm_iap_lead_technology_22,Amazon Payments,amazon_payments
+crm_iap_lead_technology_23,Amazon S3,amazon_s3
+crm_iap_lead_technology_24,Amazon Simple Email Service,amazon_ses
+crm_iap_lead_technology_25,Amazon Web Services,aws_ec2
+crm_iap_lead_technology_26,amCharts,amcharts
+crm_iap_lead_technology_27,Amplitude,amplitude
+crm_iap_lead_technology_28,Android,android
+crm_iap_lead_technology_29,Apache,apache
+crm_iap_lead_technology_30,App Nexus,app_nexus
+crm_iap_lead_technology_31,Appboy,appboy
+crm_iap_lead_technology_32,Appcues,appcues
+crm_iap_lead_technology_33,AppDynamics,appdynamics
+crm_iap_lead_technology_34,Apteligent,apteligent
+crm_iap_lead_technology_35,ASP.Net,asp_net
+crm_iap_lead_technology_36,Attribution,attribution
+crm_iap_lead_technology_37,Authorizenet,authorizenet
+crm_iap_lead_technology_38,Autopilot,autopilot
+crm_iap_lead_technology_39,Aweber,aweber
+crm_iap_lead_technology_40,Bazaarvoice,bazaarvoice
+crm_iap_lead_technology_41,Benchmarkemail,benchmarkemail
+crm_iap_lead_technology_42,Big Cartel,big_cartel
+crm_iap_lead_technology_43,Bigcommerce,bigcommerce
+crm_iap_lead_technology_44,Bing Ads,bing_ads
+crm_iap_lead_technology_45,Bing Advertiser,bing_advertiser
+crm_iap_lead_technology_46,Bing Maps,bing_maps
+crm_iap_lead_technology_47,Bloomreach,bloomreach
+crm_iap_lead_technology_48,Bluehost Hosting,bluehost_hosting
+crm_iap_lead_technology_49,Braintree,braintree
+crm_iap_lead_technology_50,Branch,branch
+crm_iap_lead_technology_51,Brightcove,brightcove
+crm_iap_lead_technology_52,Bronto,bronto
+crm_iap_lead_technology_53,Bug Herd,bug_herd
+crm_iap_lead_technology_54,Bugsnag,bugsnag
+crm_iap_lead_technology_55,C3 Metrics,c3_metrics
+crm_iap_lead_technology_56,Calq,calq
+crm_iap_lead_technology_57,Campaignmonitor,campaignmonitor
+crm_iap_lead_technology_58,Castle,castle
+crm_iap_lead_technology_59,CentOS,centos
+crm_iap_lead_technology_60,Chargify,chargify
+crm_iap_lead_technology_61,Chart Beat,chart_beat
+crm_iap_lead_technology_62,Chartio,chartio
+crm_iap_lead_technology_63,Chatlio,chatlio
+crm_iap_lead_technology_64,Chownow,chownow
+crm_iap_lead_technology_65,ClickFunnels,clickfunnels
+crm_iap_lead_technology_66,Clicktale,clicktale
+crm_iap_lead_technology_67,Clicky,clicky
+crm_iap_lead_technology_68,Cloud Flare,cloud_flare
+crm_iap_lead_technology_69,Cloudinary,cloudinary
+crm_iap_lead_technology_70,Commerce Sciences,commerce_sciences
+crm_iap_lead_technology_71,Constant Contact,constant_contact
+crm_iap_lead_technology_72,Contently,contently
+crm_iap_lead_technology_73,Convert Kit,convert_kit
+crm_iap_lead_technology_74,Convertro,convertro
+crm_iap_lead_technology_75,Crazy Egg,crazy_egg
+crm_iap_lead_technology_76,Criteo,criteo
+crm_iap_lead_technology_77,Crowdskout,crowdskout
+crm_iap_lead_technology_78,Customer.io,customer_io
+crm_iap_lead_technology_79,Dailymotion,dailymotion
+crm_iap_lead_technology_80,Debian,debian
+crm_iap_lead_technology_81,Demandbase,demandbase
+crm_iap_lead_technology_82,Demandware,demandware
+crm_iap_lead_technology_83,Digital Ocean,digital_ocean
+crm_iap_lead_technology_84,Disqus,disqus
+crm_iap_lead_technology_85,Django,django
+crm_iap_lead_technology_86,DNS Made Easy,dns_made_easy
+crm_iap_lead_technology_87,DoubleClick Ads,double_click
+crm_iap_lead_technology_88,DoubleClick Advertiser,double_click_advertiser
+crm_iap_lead_technology_89,DreamHost Hosting,dreamhost_hosting
+crm_iap_lead_technology_90,Drift,drift
+crm_iap_lead_technology_91,Drip,drip
+crm_iap_lead_technology_92,Drupal,drupal
+crm_iap_lead_technology_93,Dwolla,dwolla
+crm_iap_lead_technology_94,Dyn DNS,dyn_dns
+crm_iap_lead_technology_95,Dynamic Yield,dynamic_yield
+crm_iap_lead_technology_96,Ecwid,ecwid
+crm_iap_lead_technology_97,ElasticEmail,elasticemail
+crm_iap_lead_technology_98,Elevio,elevio
+crm_iap_lead_technology_99,Eloqua,eloqua
+crm_iap_lead_technology_100,Emma,emma
+crm_iap_lead_technology_101,Engagio,engagio
+crm_iap_lead_technology_102,Errorception,errorception
+crm_iap_lead_technology_103,Express,express
+crm_iap_lead_technology_104,Facebook Advertiser,facebook_advertiser
+crm_iap_lead_technology_105,Facebook Beacon,facebook_beacon
+crm_iap_lead_technology_106,Facebook Comments,facebook_comments
+crm_iap_lead_technology_107,Facebook Connect,facebook_connect
+crm_iap_lead_technology_108,Facebook Like Button,facebook_like_button
+crm_iap_lead_technology_109,Facebook Social Plugins,facebook_social_plugins
+crm_iap_lead_technology_110,Fedora,fedora
+crm_iap_lead_technology_111,Flowplayer,flowplayer
+crm_iap_lead_technology_112,Formstack,formstack
+crm_iap_lead_technology_113,FreeBSD,freebsd
+crm_iap_lead_technology_114,Freshdesk,freshdesk
+crm_iap_lead_technology_115,Fullcontact,fullcontact
+crm_iap_lead_technology_116,Fullstory,fullstory
+crm_iap_lead_technology_117,FusionCharts,fusioncharts
+crm_iap_lead_technology_118,Gauges,gauges
+crm_iap_lead_technology_119,Get Response,get_response
+crm_iap_lead_technology_120,Get Satisfaction,get_satisfaction
+crm_iap_lead_technology_121,Go Squared,go_squared
+crm_iap_lead_technology_122,Gocardless,gocardless
+crm_iap_lead_technology_123,GoDaddy Hosting,godaddy_hosting
+crm_iap_lead_technology_124,Godaddy Nameserver,godaddy_nameserver
+crm_iap_lead_technology_125,Google Adsense,google_adsense
+crm_iap_lead_technology_126,Google Adwords,google_adwords
+crm_iap_lead_technology_127,Google Affiliate Network,google_affiliate_network
+crm_iap_lead_technology_128,Google Analytics,google_analytics
+crm_iap_lead_technology_129,Google Apps,google_apps
+crm_iap_lead_technology_130,Google Charts,google_charts
+crm_iap_lead_technology_131,Google Cloud,google_cloud
+crm_iap_lead_technology_132,Google Forms,google_forms
+crm_iap_lead_technology_133,Google Maps,google_maps
+crm_iap_lead_technology_134,Google Tag Manager,google_tag_manager
+crm_iap_lead_technology_135,Google Website Optimizer,google_website_optimizer
+crm_iap_lead_technology_136,Google Widgets,google_widgets
+crm_iap_lead_technology_137,GraphIQ,graphiq
+crm_iap_lead_technology_138,Gravity Forms,gravity_forms
+crm_iap_lead_technology_139,Greenhouse,greenhouse
+crm_iap_lead_technology_140,Heap,heap
+crm_iap_lead_technology_141,Hello Bar,hello_bar
+crm_iap_lead_technology_142,Help Scout,help_scout
+crm_iap_lead_technology_143,Heroku,heroku
+crm_iap_lead_technology_144,Highcharts,highcharts
+crm_iap_lead_technology_145,Hotjar,hotjar
+crm_iap_lead_technology_146,Hoverowl,hoverowl
+crm_iap_lead_technology_147,HubSpot,hubspot
+crm_iap_lead_technology_148,Icims,icims
+crm_iap_lead_technology_149,Indicative,indicative
+crm_iap_lead_technology_150,Infusionsoft,infusionsoft
+crm_iap_lead_technology_151,Inside Sales,inside_sales
+crm_iap_lead_technology_152,Inspectlet,inspectlet
+crm_iap_lead_technology_153,Instagram,instagram
+crm_iap_lead_technology_154,Instagram Links,instagram_links
+crm_iap_lead_technology_155,Instart Logic,instart_logic
+crm_iap_lead_technology_156,Intense Debate,intense_debate
+crm_iap_lead_technology_157,Intercom,intercom
+crm_iap_lead_technology_158,ios,ios
+crm_iap_lead_technology_159,Iterable,iterable
+crm_iap_lead_technology_160,Java,java
+crm_iap_lead_technology_161,Jobvite,jobvite
+crm_iap_lead_technology_162,Joomla,joomla
+crm_iap_lead_technology_163,Jw Player,jw_player
+crm_iap_lead_technology_164,Kaltura,kaltura
+crm_iap_lead_technology_165,Kapost,kapost
+crm_iap_lead_technology_166,Keen IO,keen_io
+crm_iap_lead_technology_167,Kissmetrics,kiss_metrics
+crm_iap_lead_technology_168,Klaviyo,klaviyo
+crm_iap_lead_technology_169,Knowtify,knowtify
+crm_iap_lead_technology_170,Lead Dyno,lead_dyno
+crm_iap_lead_technology_171,Lever,lever
+crm_iap_lead_technology_172,Lightspeed,lightspeed
+crm_iap_lead_technology_173,LinkedIn Advertiser,linked_in_advertiser
+crm_iap_lead_technology_174,Linkwithin,linkwithin
+crm_iap_lead_technology_175,Linode Hosting,linode_hosting
+crm_iap_lead_technology_176,Live Chat,live_chat
+crm_iap_lead_technology_177,Livefyre,livefyre
+crm_iap_lead_technology_178,Liveramp,liveramp
+crm_iap_lead_technology_179,LKQD,lkqd
+crm_iap_lead_technology_180,Localytics,localytics
+crm_iap_lead_technology_181,Looker,looker
+crm_iap_lead_technology_182,Lucky Orange,lucky_orange
+crm_iap_lead_technology_183,Mad Kudu,mad_kudu
+crm_iap_lead_technology_184,Magento,magento
+crm_iap_lead_technology_185,Magento Enterprise,magento_enterprise
+crm_iap_lead_technology_186,Magento V1,magento_v1
+crm_iap_lead_technology_187,Magento V2,magento_v2
+crm_iap_lead_technology_188,Mailchimp,mailchimp
+crm_iap_lead_technology_189,Mailgun,mailgun
+crm_iap_lead_technology_190,Mailjet,mailjet
+crm_iap_lead_technology_191,Mandrill,mandrill
+crm_iap_lead_technology_192,Marin,marin
+crm_iap_lead_technology_193,Marketo,marketo
+crm_iap_lead_technology_194,Maxmind,maxmind
+crm_iap_lead_technology_195,Microsoft Azure,microsoft_azure
+crm_iap_lead_technology_196,Microsoft Exchange Online,microsoft_exchange_online
+crm_iap_lead_technology_197,Microsoft Office 365,microsoft_office_365
+crm_iap_lead_technology_198,Mindbody,mindbody
+crm_iap_lead_technology_199,Mixpanel,mixpanel
+crm_iap_lead_technology_200,Mode,mode
+crm_iap_lead_technology_201,Mouseflow,mouseflow
+crm_iap_lead_technology_202,Mousestats,mousestats
+crm_iap_lead_technology_203,My Site Auditor,my_site_auditor
+crm_iap_lead_technology_204,Namecheap Dns,namecheap_dns
+crm_iap_lead_technology_205,NationBuilder,nation_builder
+crm_iap_lead_technology_206,Neustar Ad Advisor,neustar_ad_advisor
+crm_iap_lead_technology_207,New Relic,new_relic
+crm_iap_lead_technology_208,Nextable,nextable
+crm_iap_lead_technology_209,Nginx,nginx
+crm_iap_lead_technology_210,Nosto,nosto
+crm_iap_lead_technology_211,Ns1,ns1
+crm_iap_lead_technology_212,Olark,olark
+crm_iap_lead_technology_213,Omniconvert,omniconvert
+crm_iap_lead_technology_214,Omniture (Adobe Analytics),omniture_adobe_analytics
+crm_iap_lead_technology_215,Ooyala,ooyala
+crm_iap_lead_technology_216,Open Table,open_table
+crm_iap_lead_technology_217,Optimizely,optimizely
+crm_iap_lead_technology_218,Optimonk,optimonk
+crm_iap_lead_technology_219,Oscommerce,oscommerce
+crm_iap_lead_technology_220,Outbound,outbound
+crm_iap_lead_technology_221,Outbrain Ads,outbrain_ads
+crm_iap_lead_technology_222,Outlook,outlook
+crm_iap_lead_technology_223,ownerIQ,owneriq
+crm_iap_lead_technology_224,Pardot,pardot
+crm_iap_lead_technology_225,PayPal,paypal
+crm_iap_lead_technology_226,Payza,payza
+crm_iap_lead_technology_227,Percolate,percolate
+crm_iap_lead_technology_228,Perfect Audience,perfect_audience
+crm_iap_lead_technology_229,Periscope Data,periscope_data
+crm_iap_lead_technology_230,Picreel,picreel
+crm_iap_lead_technology_231,Pingdom,pingdom
+crm_iap_lead_technology_232,Pinterest,pinterest
+crm_iap_lead_technology_233,Pipedrive,pipedrive
+crm_iap_lead_technology_234,Piwik,piwik
+crm_iap_lead_technology_235,Playwire,playwire
+crm_iap_lead_technology_236,Postmark,postmark
+crm_iap_lead_technology_237,PowerReviews,powerreviews
+crm_iap_lead_technology_238,Presta Shop,presta_shop
+crm_iap_lead_technology_239,Privy,privy
+crm_iap_lead_technology_240,Qbrick,qbrick
+crm_iap_lead_technology_241,Qualaroo,qualaroo
+crm_iap_lead_technology_242,Qualtrics,qualtrics
+crm_iap_lead_technology_243,Quantcast,quantcast
+crm_iap_lead_technology_244,Qubit,qubit
+crm_iap_lead_technology_245,Rackspace,rackspace
+crm_iap_lead_technology_246,Rackspace Email,rackspace_email
+crm_iap_lead_technology_247,Recaptcha,recaptcha
+crm_iap_lead_technology_248,Recruiterbox,recruiterbox
+crm_iap_lead_technology_249,Recurly,recurly
+crm_iap_lead_technology_250,Red Hat,red_hat
+crm_iap_lead_technology_251,ReSRCit,resrcit
+crm_iap_lead_technology_252,Resumator,resumator
+crm_iap_lead_technology_253,RetailRocket,retailrocket
+crm_iap_lead_technology_254,Rezdy,rezdy
+crm_iap_lead_technology_255,Rezgo,rezgo
+crm_iap_lead_technology_256,Robly,robly
+crm_iap_lead_technology_257,Rollbar,rollbar
+crm_iap_lead_technology_258,Route 53,aws_route_53
+crm_iap_lead_technology_259,Ruby On Rails,ruby_on_rails
+crm_iap_lead_technology_260,Salesforce,salesforce
+crm_iap_lead_technology_261,Salesmachine,salesmachine
+crm_iap_lead_technology_262,Salsa,salsa
+crm_iap_lead_technology_263,Satismeter,satismeter
+crm_iap_lead_technology_264,Segment,segment
+crm_iap_lead_technology_265,Sendgrid,sendgrid
+crm_iap_lead_technology_266,Sentry,sentry
+crm_iap_lead_technology_267,Sessioncam,sessioncam
+crm_iap_lead_technology_268,Sharepoint,sharepoint
+crm_iap_lead_technology_269,Sharp Spring,sharp_spring
+crm_iap_lead_technology_270,Shopify,shopify
+crm_iap_lead_technology_271,Shopify Plus,shopify_plus
+crm_iap_lead_technology_272,Shopware,shopware
+crm_iap_lead_technology_273,Sidecar,sidecar
+crm_iap_lead_technology_274,Silkroad,silkroad
+crm_iap_lead_technology_275,Simplicant,simplicant
+crm_iap_lead_technology_276,Slack,slack
+crm_iap_lead_technology_277,Smartlook,smartlook
+crm_iap_lead_technology_278,Snowplow Analytics,snowplow_analytics
+crm_iap_lead_technology_279,Sociomantic,sociomantic
+crm_iap_lead_technology_280,Socket.io,socket_io
+crm_iap_lead_technology_281,Softlayer Hosting,softlayer_hosting
+crm_iap_lead_technology_282,Squarespace,squarespace
+crm_iap_lead_technology_283,SteelHouse,steel_house
+crm_iap_lead_technology_284,Stripe,stripe
+crm_iap_lead_technology_285,Success Factors,success_factors
+crm_iap_lead_technology_286,Sumo,sumo
+crm_iap_lead_technology_287,Survey Monkey,survey_monkey
+crm_iap_lead_technology_288,Tableau,tableau
+crm_iap_lead_technology_289,Taboola Ads,taboola_ads
+crm_iap_lead_technology_290,Taleo,taleo
+crm_iap_lead_technology_291,Talkable,talkable
+crm_iap_lead_technology_292,Tawk,tawk
+crm_iap_lead_technology_293,Tealium,tealium
+crm_iap_lead_technology_294,Terminus,terminus
+crm_iap_lead_technology_295,Top Producer,top_producer
+crm_iap_lead_technology_296,Totango,totango
+crm_iap_lead_technology_297,Tout,tout
+crm_iap_lead_technology_298,Toutapp,toutapp
+crm_iap_lead_technology_299,TowerData,towerdata
+crm_iap_lead_technology_300,Track JS,track_js
+crm_iap_lead_technology_301,Trustpilot,trustpilot
+crm_iap_lead_technology_302,Twitter Advertiser,twitter_advertiser
+crm_iap_lead_technology_303,Twitter Badge,twitter_badge
+crm_iap_lead_technology_304,Twitter Button,twitter_button
+crm_iap_lead_technology_305,Typeform,typeform
+crm_iap_lead_technology_306,Typekit By Adobe,typekit_by_adobe
+crm_iap_lead_technology_307,Uber Cart,uber_cart
+crm_iap_lead_technology_308,Ubuntu,ubuntu
+crm_iap_lead_technology_309,Ultipro,ultipro
+crm_iap_lead_technology_310,Unix,unix
+crm_iap_lead_technology_311,UserVoice,user_voice
+crm_iap_lead_technology_312,Vero,vero
+crm_iap_lead_technology_313,Verticalresponse,verticalresponse
+crm_iap_lead_technology_314,Video.js,videojs
+crm_iap_lead_technology_315,Vidyard,vidyard
+crm_iap_lead_technology_316,Vimeo,vimeo
+crm_iap_lead_technology_317,Virtue Mart,virtue_mart
+crm_iap_lead_technology_318,Visual IQ,visual_iq
+crm_iap_lead_technology_319,Visual Website Optimizer,visual_website_optimizer
+crm_iap_lead_technology_320,Volusion,volusion
+crm_iap_lead_technology_321,Vzaar,vzaar
+crm_iap_lead_technology_322,WebEngage,webengage
+crm_iap_lead_technology_323,Weebly,weebly
+crm_iap_lead_technology_324,Wistia,wistia
+crm_iap_lead_technology_325,Wix Stores,wix_stores
+crm_iap_lead_technology_326,Woo Commerce,woo_commerce
+crm_iap_lead_technology_327,Woopra,woopra
+crm_iap_lead_technology_328,Wootric,wootric
+crm_iap_lead_technology_329,Wordpress,wordpress
+crm_iap_lead_technology_330,Workable,workable
+crm_iap_lead_technology_331,Wp Engine,wp_engine
+crm_iap_lead_technology_332,Wufoo,wufoo
+crm_iap_lead_technology_333,xt:Commerce,xt_commerce
+crm_iap_lead_technology_334,Yahoo Stores,yahoo_stores
+crm_iap_lead_technology_335,Yandex Metrica,yandex_metrica
+crm_iap_lead_technology_336,Yelp Seatme,yelp_seatme
+crm_iap_lead_technology_337,Yesware,yesware
+crm_iap_lead_technology_338,Yieldify,yieldify
+crm_iap_lead_technology_339,Yotpo,yotpo
+crm_iap_lead_technology_340,Youtube,youtube
+crm_iap_lead_technology_341,Zeit Now,zeit_now
+crm_iap_lead_technology_342,Zen Cart,zen_cart
+crm_iap_lead_technology_343,Zendesk,zendesk
+crm_iap_lead_technology_344,Zenreach,zenreach
+crm_iap_lead_technology_345,Zopim,zopim
+crm_iap_lead_technology_346,Zuora,zuora
+crm_iap_lead_technology_347,Zype,zype
diff --git a/addons/crm_iap_lead/data/ir_sequence_data.xml b/addons/crm_iap_lead/data/ir_sequence_data.xml
new file mode 100644
index 00000000000..89be4f1607b
--- /dev/null
+++ b/addons/crm_iap_lead/data/ir_sequence_data.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Lead Mining Request
+ crm.iap.lead.mining.request
+ LMR
+ 3
+
+
+
+
+
diff --git a/addons/crm_iap_lead/models/__init__.py b/addons/crm_iap_lead/models/__init__.py
index 5fc7bce13c3..d529ee24678 100644
--- a/addons/crm_iap_lead/models/__init__.py
+++ b/addons/crm_iap_lead/models/__init__.py
@@ -2,3 +2,5 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import crm_lead
from . import crm_iap_lead
+from . import crm_iap_lead_helpers
+from . import crm_iap_lead_mining_request
diff --git a/addons/crm_iap_lead/models/crm_iap_lead.py b/addons/crm_iap_lead/models/crm_iap_lead.py
index 1383027b560..0e3d60febd9 100644
--- a/addons/crm_iap_lead/models/crm_iap_lead.py
+++ b/addons/crm_iap_lead/models/crm_iap_lead.py
@@ -48,3 +48,16 @@ class PeopleSeniority(models.Model):
@api.depends('name')
def name_get(self):
return [(seniority.id, seniority.name.replace('_', ' ').title()) for seniority in self]
+
+
+class TechnologyTag(models.Model):
+ """ Technology Tags of Clearbit """
+ _name = 'crm.iap.lead.technology'
+ _description = 'Technology Tag'
+
+ name = fields.Char(string='Name', required=True, translate=True)
+ tech_tag = fields.Char(string="Tech Tag", required=True)
+
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)', 'Technology tag name already exists!'),
+ ]
diff --git a/addons/crm_iap_lead/models/crm_iap_lead_helpers.py b/addons/crm_iap_lead/models/crm_iap_lead_helpers.py
new file mode 100644
index 00000000000..3a42c0cbf97
--- /dev/null
+++ b/addons/crm_iap_lead/models/crm_iap_lead_helpers.py
@@ -0,0 +1,121 @@
+from math import floor, log10
+from odoo import api, models
+
+
+class CRMHelpers(models.Model):
+ _name = 'crm.iap.lead.helpers'
+ _description = 'Helper methods for crm_iap_lead modules'
+
+ @api.model
+ def notify_no_more_credit(self, service_name, model_name, notification_parameter):
+ """
+ Notify about the number of credit.
+ In order to avoid to spam people each hour, an ir.config_parameter is set
+ """
+ already_notified = self.env['ir.config_parameter'].sudo().get_param(notification_parameter, False)
+ if already_notified:
+ return
+ mail_template = self.env.ref('crm_iap_lead.lead_generation_no_credits')
+ iap_account = self.env['iap.account'].search([('service_name', '=', service_name)], limit=1)
+ # Get the email address of the creators of the records
+ res = self.env[model_name].search_read([], ['create_uid'])
+ uids = set(r['create_uid'][0] for r in res if r.get('create_uid'))
+ res = self.env['res.users'].search_read([('id', 'in', list(uids))], ['email'])
+ emails = set(r['email'] for r in res if r.get('email'))
+
+ mail_values = mail_template.generate_email(iap_account.id)
+ mail_values['email_to'] = ','.join(emails)
+ mail = self.env['mail.mail'].create(mail_values)
+ mail.send()
+ self.env['ir.config_parameter'].sudo().set_param(notification_parameter, True)
+
+ @api.model
+ def lead_vals_from_response(self, lead_type, team_id, tag_ids, user_id, company_data, people_data):
+ country_id = self.env['res.country'].search([('code', '=', company_data['country_code'])]).id
+ website_url = 'https://www.%s' % company_data['domain'] if company_data['domain'] else False
+ lead_vals = {
+ # Lead vals from record itself
+ 'type': lead_type,
+ 'team_id': team_id,
+ 'tag_ids': [(6, 0, tag_ids)],
+ 'user_id': user_id,
+ 'reveal_id': company_data['clearbit_id'],
+ # Lead vals from data
+ 'name': company_data['name'],
+ 'partner_name': company_data['legal_name'] or company_data['name'],
+ 'email_from': ",".join(company_data['email'] or []),
+ 'phone': company_data['phone'] or (company_data['phone_numbers'] and company_data['phone_numbers'][0]) or '',
+ 'website': website_url,
+ 'street': company_data['location'],
+ 'city': company_data['city'],
+ 'zip': company_data['postal_code'],
+ 'country_id': country_id,
+ 'state_id': self._find_state_id(company_data['state_code'], country_id),
+ 'description': self._prepare_lead_description(company_data),
+ }
+
+ # If type is people then add first contact in lead data
+ if people_data:
+ lead_vals.update({
+ 'contact_name': people_data[0]['full_name'],
+ 'email_from': people_data[0]['email'],
+ 'function': people_data[0]['title'],
+ })
+ return lead_vals
+
+ @api.model
+ def _find_state_id(self, state_code, country_id):
+ state_id = self.env['res.country.state'].search([('code', '=', state_code), ('country_id', '=', country_id)])
+ if state_id:
+ return state_id.id
+ return False
+
+ @api.model
+ def _prepare_lead_description(self, reveal_data):
+ description = ''
+ if reveal_data['sector']:
+ description += reveal_data['sector']
+ if reveal_data['website_title']:
+ description += '\n' + reveal_data['website_title']
+ if reveal_data['twitter_bio']:
+ description += '\n' + "Twitter Bio: " + reveal_data['twitter_bio']
+ if reveal_data['twitter_followers']:
+ description += ('\nTwitter %s followers, %s \n') % (reveal_data['twitter_followers'], reveal_data['twitter_location'] or '')
+
+ numbers = ['raised', 'market_cap', 'employees', 'estimated_annual_revenue']
+ millnames = ['', ' K', ' M', ' B', 'T']
+
+ def millify(n):
+ try:
+ n = float(n)
+ millidx = max(0, min(len(millnames) - 1, int(floor(0 if n == 0 else log10(abs(n)) / 3))))
+ return '{:.0f}{}'.format(n / 10**(3 * millidx), millnames[millidx])
+ except Exception:
+ return n
+
+ for key in numbers:
+ if reveal_data.get(key):
+ description += ' %s : %s,' % (key.replace('_', ' ').title(), millify(reveal_data[key]))
+ return description
+
+ @api.model
+ def format_data_for_message_post(self, company_data, people_data):
+ log_data = {
+ 'twitter': company_data['twitter'],
+ 'description': company_data['description'],
+ 'logo': company_data['logo'],
+ 'name': company_data['name'],
+ 'phone_numbers': company_data['phone_numbers'],
+ 'facebook': company_data['facebook'],
+ 'linkedin': company_data['linkedin'],
+ 'crunchbase': company_data['crunchbase'],
+ 'tech': [t.replace('_', ' ').title() for t in company_data['tech']],
+ 'people_data': people_data,
+ }
+ timezone = company_data['timezone']
+ if timezone:
+ log_data.update({
+ 'timezone': timezone.replace('_', ' ').title(),
+ 'timezone_url': company_data['timezone_url'],
+ })
+ return log_data
diff --git a/addons/crm_iap_lead/models/crm_iap_lead_mining_request.py b/addons/crm_iap_lead/models/crm_iap_lead_mining_request.py
new file mode 100644
index 00000000000..84b23c9151e
--- /dev/null
+++ b/addons/crm_iap_lead/models/crm_iap_lead_mining_request.py
@@ -0,0 +1,233 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import logging
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+from odoo.addons.iap import jsonrpc, InsufficientCreditError
+
+_logger = logging.getLogger(__name__)
+
+DEFAULT_ENDPOINT = 'https://iap-services.odoo.com'
+
+MAX_LEAD = 200
+MAX_CONTACT = 5
+
+CREDIT_PER_COMPANY = 1
+CREDIT_PER_CONTACT = 1
+
+
+class CRMLeadMiningRequest(models.Model):
+ _name = 'crm.iap.lead.mining.request'
+ _description = 'CRM Lead Mining Request'
+
+ def _default_lead_type(self):
+ if self.env.user.has_group('crm.group_use_lead'):
+ return 'lead'
+ else:
+ return 'opportunity'
+
+ name = fields.Char(string='Request Number', required=True, readonly=True, default=lambda self: _('New'), copy=False)
+ state = fields.Selection([('draft', 'Draft'), ('done', 'Done'), ('error', 'Error')], string='Status', required=True, default='draft')
+
+ # Request Data
+ lead_number = fields.Integer(string='Number of Leads', required=True, default=10)
+ search_type = fields.Selection([('companies', 'Companies'), ('people', 'Companies and their Contacts')], string='Target', required=True, default='companies')
+ error = fields.Text(string='Error', readonly=True)
+
+ # Lead / Opportunity Data
+ lead_type = fields.Selection([('lead', 'Lead'), ('opportunity', 'Opportunity')], string='Type', required=True, default=_default_lead_type)
+ team_id = fields.Many2one('crm.team', string='Sales Team', domain="[('use_opportunities', '=', True)]")
+ user_id = fields.Many2one('res.users', string='Salesperson')
+ tag_ids = fields.Many2many('crm.lead.tag', string='Tags')
+ lead_ids = fields.One2many('crm.lead', 'lead_mining_request_id', string='Generated Lead / Opportunity')
+ leads_count = fields.Integer(compute='_compute_leads_count', string='Number of Generated Leads')
+
+ # Company Criteria Filter
+ filter_on_size = fields.Boolean(string='Filter on Size', default=False)
+ company_size_min = fields.Integer(string='Size', default=1)
+ company_size_max = fields.Integer(default=1000)
+ country_ids = fields.Many2many('res.country', string='Countries')
+ state_ids = fields.Many2many('res.country.state', string='States')
+ industry_ids = fields.Many2many('crm.iap.lead.industry', string='Industries')
+ technology_ids = fields.Many2many('crm.iap.lead.technology', string='Technologies')
+
+ # Contact Generation Filter
+ contact_number = fields.Integer(string='Number of Contacts', default=1)
+ contact_filter_type = fields.Selection([('role', 'Role'), ('seniority', 'Seniority')], string='Filter on', default='role')
+ preferred_role_id = fields.Many2one('crm.iap.lead.role', string='Preferred Role')
+ role_ids = fields.Many2many('crm.iap.lead.role', string='Other Roles')
+ seniority_id = fields.Many2one('crm.iap.lead.seniority', string='Seniority')
+
+ # Fields for the blue tooltip
+ lead_number_info = fields.Integer(string='Number of Leads ', related='lead_number', readonly=True)
+ lead_total_credit = fields.Integer(compute='_compute_lead_total_credit')
+ contact_credit_per_company = fields.Integer(compute='_compute_contact_credit_per_company')
+ contact_total_credit = fields.Integer(compute='_compute_contact_total_credit')
+
+ @api.depends('lead_number')
+ def _compute_lead_total_credit(self):
+ for req in self:
+ req.lead_total_credit = CREDIT_PER_COMPANY * req.lead_number
+
+ @api.depends('contact_number')
+ def _compute_contact_credit_per_company(self):
+ for req in self:
+ req.contact_credit_per_company = CREDIT_PER_CONTACT * req.contact_number
+
+ @api.depends('contact_number', 'lead_number')
+ def _compute_contact_total_credit(self):
+ for req in self:
+ req.contact_total_credit = CREDIT_PER_CONTACT * req.contact_number * req.lead_number
+
+ @api.depends('lead_ids')
+ def _compute_leads_count(self):
+ for req in self:
+ req.leads_count = len(req.lead_ids)
+
+ @api.onchange('lead_number')
+ def _onchange_lead_number(self):
+ if self.lead_number <= 0:
+ self.lead_number = 1
+ elif self.lead_number > MAX_LEAD:
+ self.lead_number = MAX_LEAD
+
+ @api.onchange('contact_number')
+ def _onchange_contact_number(self):
+ if self.contact_number <= 0:
+ self.contact_number = 1
+ elif self.contact_number > MAX_CONTACT:
+ self.contact_number = MAX_CONTACT
+
+ @api.onchange('country_ids')
+ def _onchange_country_ids(self):
+ self.state_ids = []
+
+ @api.onchange('company_size_min')
+ def _onchange_company_size_min(self):
+ if self.company_size_min <= 0:
+ self.company_size_min = 1
+ elif self.company_size_min > self.company_size_max:
+ self.company_size_min = self.company_size_max
+
+ @api.onchange('company_size_max')
+ def _onchange_company_size_max(self):
+ if self.company_size_max < self.company_size_min:
+ self.company_size_max = self.company_size_min
+
+ def _prepare_iap_payload(self):
+ """
+ This will prepare the data to send to the server
+ """
+ self.ensure_one()
+ payload = {'lead_number': self.lead_number,
+ 'search_type': self.search_type,
+ 'countries': self.country_ids.mapped('code')}
+ if self.state_ids:
+ payload['states'] = self.state_ids.mapped('code')
+ if self.filter_on_size:
+ payload.update({'company_size_min': self.company_size_min,
+ 'company_size_max': self.company_size_max})
+ if self.technology_ids:
+ payload['technology_tags'] = self.technology_ids.mapped('tech_tag')
+ if self.search_type == 'people':
+ payload.update({'contact_number': self.contact_number,
+ 'contact_filter_type': self.contact_filter_type})
+ if self.contact_filter_type == 'role':
+ payload.update({'preferred_role': self.preferred_role_id.reveal_id,
+ 'other_roles': self.role_ids.mapped('reveal_id')})
+ elif self.contact_filter_type == 'seniority':
+ payload['seniority'] = self.seniority_id.reveal_id
+ return payload
+
+ def _perform_request(self):
+ """
+ This will perform the request and create the corresponding leads.
+ The user will be notified if he hasn't enough credits.
+ """
+ server_payload = self._prepare_iap_payload()
+ reveal_account = self.env['iap.account'].get('reveal')
+ dbuuid = self.env['ir.config_parameter'].sudo().get_param('database.uuid')
+ endpoint = self.env['ir.config_parameter'].sudo().get_param('reveal.endpoint', DEFAULT_ENDPOINT) + '/iap/clearbit/1/lead_mining_request'
+ params = {
+ 'account_token': reveal_account.account_token,
+ 'dbuuid': dbuuid,
+ 'data': server_payload
+ }
+ try:
+ response = jsonrpc(endpoint, params=params, timeout=300)
+ return response['data']
+ except InsufficientCreditError as e:
+ self.error = 'Insufficient credits. Recharge your account and retry.'
+ self.state = 'error'
+ self._cr.commit()
+ raise e
+
+ @api.multi
+ def _create_leads_from_response(self, result):
+ """ This method will get the response from the service and create the leads accordingly """
+ self.ensure_one()
+ lead_vals = []
+ messages_to_post = {}
+ for data in result:
+ lead_vals.append(self._lead_vals_from_response(data))
+ messages_to_post[data['company_data']['clearbit_id']] = self.env['crm.iap.lead.helpers'].format_data_for_message_post(data['company_data'], data.get('people_data'))
+ leads = self.env['crm.lead'].create(lead_vals)
+ for lead in leads:
+ if messages_to_post.get(lead.reveal_id):
+ lead.message_post_with_view('crm_iap_lead.lead_message_template', values=messages_to_post[lead.reveal_id], subtype_id=self.env.ref('mail.mt_note').id)
+
+ # Methods responsible for format response data into valid odoo lead data
+ @api.model
+ def _lead_vals_from_response(self, data):
+ self.ensure_one()
+ company_data = data.get('company_data')
+ people_data = data.get('people_data')
+ lead_vals = self.env['crm.iap.lead.helpers'].lead_vals_from_response(self.lead_type, self.team_id.id, self.tag_ids.ids, self.user_id.id, company_data, people_data)
+ lead_vals['lead_mining_request_id'] = self.id
+ return lead_vals
+
+ @api.multi
+ def action_draft(self):
+ self.ensure_one()
+ self.name = _('New')
+ self.state = 'draft'
+
+ @api.multi
+ def action_submit(self):
+ self.ensure_one()
+ if self.name == _('New'):
+ self.name = self.env['ir.sequence'].next_by_code('crm.iap.lead.mining.request') or _('New')
+ results = self._perform_request()
+ if results:
+ self._create_leads_from_response(results)
+ self.state = 'done'
+ if self.lead_type == 'lead':
+ return self.action_get_lead_action()
+ elif self.lead_type == 'opportunity':
+ return self.action_get_opportunity_action()
+
+ @api.multi
+ def action_get_lead_action(self):
+ self.ensure_one()
+ action = self.env.ref('crm.crm_lead_all_leads').read()[0]
+ action['domain'] = [('id', 'in', self.lead_ids.ids), ('type', '=', 'lead')]
+ action['help'] = _("""
+ No leads found
+
+ No leads could be generated according to your search criteria
+
""")
+ return action
+
+ @api.multi
+ def action_get_opportunity_action(self):
+ self.ensure_one()
+ action = self.env.ref('crm.crm_lead_opportunities').read()[0]
+ action['domain'] = [('id', 'in', self.lead_ids.ids), ('type', '=', 'opportunity')]
+ action['help'] = _("""
+ No opportunities found
+
+ No opportunities could be generated according to your search criteria
+
""")
+ return action
diff --git a/addons/crm_iap_lead/models/crm_lead.py b/addons/crm_iap_lead/models/crm_lead.py
index 44fabf71571..bbf70174ef7 100644
--- a/addons/crm_iap_lead/models/crm_lead.py
+++ b/addons/crm_iap_lead/models/crm_lead.py
@@ -8,3 +8,4 @@ class Lead(models.Model):
_inherit = 'crm.lead'
reveal_id = fields.Char(string='Reveal ID', index=True)
+ lead_mining_request_id = fields.Many2one('crm.iap.lead.mining.request', string='Lead Mining Request', index=True)
diff --git a/addons/crm_iap_lead/security/ir.model.access.csv b/addons/crm_iap_lead/security/ir.model.access.csv
index 84384e78140..e4e857bc2d3 100644
--- a/addons/crm_iap_lead/security/ir.model.access.csv
+++ b/addons/crm_iap_lead/security/ir.model.access.csv
@@ -3,4 +3,5 @@ access_crm_iap_lead_industry,access_crm_iap_lead_industry,model_crm_iap_lead_ind
access_crm_iap_lead_role,access_crm_iap_lead_role,model_crm_iap_lead_role,sales_team.group_sale_manager,1,1,1,1
access_crm_iap_lead_seniority,access_crm_iap_lead_seniority,model_crm_iap_lead_seniority,sales_team.group_sale_manager,1,1,1,1
access_crm_iap_lead_technology,access_crm_iap_lead_technology,model_crm_iap_lead_technology,sales_team.group_sale_manager,1,1,1,1
-access_crm_iap_lead_request,access_crm_iap_lead_request,model_crm_iap_lead_request,sales_team.group_sale_manager,1,1,1,1
+access_crm_iap_lead_mining_request,access_crm_iap_lead_mining_request,model_crm_iap_lead_mining_request,sales_team.group_sale_manager,1,1,1,1
+access_crm_iap_lead_helpers,access_crm_iap_lead_helpers,model_crm_iap_lead_helpers,,0,0,0,0
diff --git a/addons/crm_iap_lead/static/src/js/leads_tree_generate_leads.js b/addons/crm_iap_lead/static/src/js/leads_tree_generate_leads.js
new file mode 100644
index 00000000000..27059c28893
--- /dev/null
+++ b/addons/crm_iap_lead/static/src/js/leads_tree_generate_leads.js
@@ -0,0 +1,76 @@
+odoo.define('crm.leads.tree', function (require) {
+"use strict";
+ var ListController = require('web.ListController');
+ var ListView = require('web.ListView');
+
+ var KanbanController = require('web.KanbanController');
+ var KanbanView = require('web.KanbanView');
+
+ var viewRegistry = require('web.view_registry');
+
+ function renderGenerateLeadsButton() {
+ if (this.$buttons) {
+ var self = this;
+ var lead_type = self.initialState.getContext()['default_type'];
+ this.$buttons.on('click', '.o_button_generate_leads', function () {
+ self.do_action({
+ name: 'Generate Leads',
+ type: 'ir.actions.act_window',
+ res_model: 'crm.iap.lead.mining.request',
+ target: 'new',
+ views: [[false, 'form']],
+ context: {'is_modal': true, 'default_lead_type': lead_type},
+ });
+ });
+ }
+ }
+
+ var LeadMiningRequestListController = ListController.extend({
+ willStart: function() {
+ var self = this;
+ var ready = this.getSession().user_has_group('sales_team.group_sale_manager')
+ .then(function (is_sale_manager) {
+ if (is_sale_manager) {
+ self.buttons_template = 'LeadMiningRequestListView.buttons';
+ }
+ });
+ return $.when(this._super.apply(this, arguments), ready);
+ },
+ renderButtons: function () {
+ this._super.apply(this, arguments);
+ renderGenerateLeadsButton.apply(this, arguments);
+ }
+ });
+
+ var LeadMiningRequestListView = ListView.extend({
+ config: _.extend({}, ListView.prototype.config, {
+ Controller: LeadMiningRequestListController,
+ }),
+ });
+
+ var LeadMiningRequestKanbanController = KanbanController.extend({
+ willStart: function() {
+ var self = this;
+ var ready = this.getSession().user_has_group('sales_team.group_sale_manager')
+ .then(function (is_sale_manager) {
+ if (is_sale_manager) {
+ self.buttons_template = 'LeadMiningRequestKanbanView.buttons';
+ }
+ });
+ return $.when(this._super.apply(this, arguments), ready);
+ },
+ renderButtons: function () {
+ this._super.apply(this, arguments);
+ renderGenerateLeadsButton.apply(this, arguments);
+ }
+ });
+
+ var LeadMiningRequestKanbanView = KanbanView.extend({
+ config: _.extend({}, KanbanView.prototype.config, {
+ Controller: LeadMiningRequestKanbanController,
+ }),
+ });
+
+ viewRegistry.add('crm_iap_lead_mining_request_tree', LeadMiningRequestListView);
+ viewRegistry.add('crm_iap_lead_mining_request_kanban', LeadMiningRequestKanbanView);
+});
diff --git a/addons/crm_iap_lead/static/src/xml/leads_tree_generate_leads_views.xml b/addons/crm_iap_lead/static/src/xml/leads_tree_generate_leads_views.xml
new file mode 100644
index 00000000000..b431e02601c
--- /dev/null
+++ b/addons/crm_iap_lead/static/src/xml/leads_tree_generate_leads_views.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+ if (window.odoo._modules.indexOf("base_import") >= 0) {
+ r.push(context.engine.tools.call(context, 'ImportView.import_button', dict));
+ };
+
+
+
+
+
+
+
+
+ if (window.odoo._modules.indexOf("base_import") >= 0) {
+ r.push(context.engine.tools.call(context, 'ImportView.import_button', dict));
+ };
+
+
+
+
diff --git a/addons/crm_iap_lead/views/crm_iap_lead_templates.xml b/addons/crm_iap_lead/views/crm_iap_lead_templates.xml
new file mode 100644
index 00000000000..d6844a6a242
--- /dev/null
+++ b/addons/crm_iap_lead/views/crm_iap_lead_templates.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/addons/crm_iap_lead/views/crm_iap_lead_views.xml b/addons/crm_iap_lead/views/crm_iap_lead_views.xml
new file mode 100644
index 00000000000..6a61b35bb21
--- /dev/null
+++ b/addons/crm_iap_lead/views/crm_iap_lead_views.xml
@@ -0,0 +1,183 @@
+
+
+
+ crm.iap.lead.mining.request.form
+ crm.iap.lead.mining.request
+
+
+
+
+
+
+ crm.iap.lead.mining.request.tree
+ crm.iap.lead.mining.request
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ crm.iap.lead.mining.request.search
+ crm.iap.lead.mining.request
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lead Mining Requests
+ crm.iap.lead.mining.request
+ tree,form
+ form
+
+
+
+
+
+
+
+
diff --git a/addons/crm_iap_lead/views/crm_lead_view.xml b/addons/crm_iap_lead/views/crm_lead_view.xml
new file mode 100644
index 00000000000..9386b1979e0
--- /dev/null
+++ b/addons/crm_iap_lead/views/crm_lead_view.xml
@@ -0,0 +1,47 @@
+
+
+
+
+ crm.opportunity.inherited.tree
+ crm.lead
+
+
+
+ crm_iap_lead_mining_request_tree
+
+
+
+
+
+ crm.opportunity.inherited.kanban
+ crm.lead
+
+
+
+ crm_iap_lead_mining_request_kanban
+
+
+
+
+
+ crm.lead.inherited.tree
+ crm.lead
+
+
+
+ crm_iap_lead_mining_request_tree
+
+
+
+
+
+ crm.lead.inherited.kanban
+ crm.lead
+
+
+
+ crm_iap_lead_mining_request_kanban
+
+
+
+
diff --git a/addons/crm_iap_lead/views/res_config_settings_views.xml b/addons/crm_iap_lead/views/res_config_settings_views.xml
new file mode 100644
index 00000000000..01888e3cf9e
--- /dev/null
+++ b/addons/crm_iap_lead/views/res_config_settings_views.xml
@@ -0,0 +1,13 @@
+
+
+
+ res.config.settings.view.form.inherit.crm.iap.lead
+ res.config.settings
+
+
+
+
+
+
+
+
diff --git a/addons/crm_iap_lead_website/models/crm_reveal_rule.py b/addons/crm_iap_lead_website/models/crm_reveal_rule.py
index a7e05762e2a..c0744e7a053 100644
--- a/addons/crm_iap_lead_website/models/crm_reveal_rule.py
+++ b/addons/crm_iap_lead_website/models/crm_reveal_rule.py
@@ -6,7 +6,6 @@ import itertools
import logging
import re
from dateutil.relativedelta import relativedelta
-from math import floor, log10
from odoo import api, fields, models, tools, _
from odoo.addons.iap import jsonrpc
@@ -316,35 +315,12 @@ class CRMRevealRule(models.Model):
'reveal_state': 'not_found'
})
if result.get('credit_error'):
- self._notify_no_more_credit()
+ self.env['crm.iap.lead.helpers'].notify_no_more_credit('reveal', self._name, 'reveal.already_notified')
return False
else:
self.env['ir.config_parameter'].sudo().set_param('reveal.already_notified', False)
return True
- def _notify_no_more_credit(self):
- """
- Notify about the number of credit.
- In order to avoid to spam people each hour, an ir.config_parameter is set
- """
- already_notified = self.env['ir.config_parameter'].sudo().get_param('reveal.already_notified', False)
- if already_notified:
- return
- mail_template = self.env.ref('crm_iap_lead.lead_generation_no_credits')
- iap_account = self.env['iap.account'].search([('service_name', '=', 'reveal')], limit=1)
- # Get the email address of the creators of the Lead Generation Rules
- res = self.env['crm.reveal.rule'].search_read([], ['create_uid'])
- uids = set(r['create_uid'][0] for r in res if r.get('create_uid'))
- res = self.env['res.users'].search_read([('id', 'in', list(uids))], ['email'])
- emails = set(r['email'] for r in res if r.get('email'))
-
- mail_values = mail_template.generate_email(iap_account.id)
- mail_values['email_to'] = ','.join(emails)
- mail = self.env['mail.mail'].create(mail_values)
- mail.send()
- self.env['ir.config_parameter'].sudo().set_param('reveal.already_notified', True)
-
-
def _create_lead_from_response(self, result):
""" This method will get response from service and create the lead accordingly """
if result['rule_id']:
@@ -365,7 +341,7 @@ class CRMRevealRule(models.Model):
lead = self.env['crm.lead'].create(lead_vals)
lead.message_post_with_view(
'crm_iap_lead.lead_message_template',
- values=self._format_data_for_message_post(result),
+ values=self.env['crm.iap.lead.helpers'].format_data_for_message_post(result['reveal_data'], result.get('people_data')),
subtype_id=self.env.ref('mail.mt_note').id
)
return lead
@@ -373,100 +349,19 @@ class CRMRevealRule(models.Model):
# Methods responsible for format response data in to valid odoo lead data
def _lead_vals_from_response(self, result):
self.ensure_one()
- reveal_data = result['reveal_data']
+ company_data = result['reveal_data']
people_data = result.get('people_data')
- country_id = self.env['res.country'].search([('code', '=', reveal_data['country_code'])]).id
- website_url = 'https://www.%s' % reveal_data['domain'] if reveal_data['domain'] else False
- lead_vals = {
- # Lead vals from rule itself
- 'type': self.lead_type,
- 'team_id': self.team_id.id,
- 'tag_ids': [(6, 0, self.tag_ids.ids)],
+ lead_vals = self.env['crm.iap.lead.helpers'].lead_vals_from_response(self.lead_type, self.team_id.id, self.tag_ids.ids, self.user_id.id, company_data, people_data)
+
+ lead_vals.update({
'priority': self.priority,
- 'user_id': self.user_id.id,
'reveal_ip': result['ip'],
'reveal_rule_id': self.id,
- 'reveal_id': result['clearbit_id'],
'referred': 'Website Visitor',
- # Lead vals from response
- 'name': reveal_data['name'],
'reveal_iap_credits': result['credit'],
- 'partner_name': reveal_data['legal_name'] or reveal_data['name'],
- 'email_from': ",".join(reveal_data['email'] or []),
- 'phone': reveal_data['phone'] or (reveal_data['phone_numbers'] and reveal_data['phone_numbers'][0]) or '',
- 'website': website_url,
- 'street': reveal_data['location'],
- 'city': reveal_data['city'],
- 'zip': reveal_data['postal_code'],
- 'country_id': country_id,
- 'state_id': self._find_state_id(reveal_data['state_name'], reveal_data['state_code'], country_id),
- 'description': self._prepare_lead_description(reveal_data),
- }
+ })
if self.suffix:
lead_vals['name'] = '%s - %s' % (lead_vals['name'], self.suffix)
- # If type is people then add first contact in lead data
- if people_data:
- lead_vals.update({
- 'contact_name': people_data[0]['full_name'],
- 'email_from': people_data[0]['email'],
- 'function': people_data[0]['title'],
- })
return lead_vals
-
- def _find_state_id(self, state_code, state_name, country_id):
- state_id = self.env['res.country.state'].search([('code', '=', state_code), ('country_id', '=', country_id)])
- if state_id:
- return state_id.id
- return False
-
- def _prepare_lead_description(self, reveal_data):
- description = ''
- if reveal_data['sector']:
- description += reveal_data['sector']
- if reveal_data['website_title']:
- description += '\n' + reveal_data['website_title']
- if reveal_data['twitter_bio']:
- description += '\n' + "Twitter Bio: " + reveal_data['twitter_bio']
- if reveal_data['twitter_followers']:
- description += ('\nTwitter %s followers, %s \n') % (reveal_data['twitter_followers'], reveal_data['twitter_location'] or '')
-
- numbers = ['raised', 'market_cap', 'employees', 'estimated_annual_revenue']
- millnames = ['', ' K', ' M', ' B', 'T']
-
- def millify(n):
- try:
- n = float(n)
- millidx = max(0, min(len(millnames) - 1, int(floor(0 if n == 0 else log10(abs(n)) / 3))))
- return '{:.0f}{}'.format(n / 10**(3 * millidx), millnames[millidx])
- except Exception:
- return n
-
- for key in numbers:
- if reveal_data.get(key):
- description += ' %s : %s,' % (key.replace('_', ' ').title(), millify(reveal_data[key]))
- return description
-
- def _format_data_for_message_post(self, result):
- reveal_data = result['reveal_data']
- people_data = result.get('people_data')
- log_data = {
- 'twitter': reveal_data['twitter'],
- 'description': reveal_data['description'],
- 'logo': reveal_data['logo'],
- 'name': reveal_data['name'],
- 'phone_numbers': reveal_data['phone_numbers'],
- 'facebook': reveal_data['facebook'],
- 'linkedin': reveal_data['linkedin'],
- 'crunchbase': reveal_data['crunchbase'],
- 'tech': [t.replace('_', ' ').title() for t in reveal_data['tech']],
- 'people_data': people_data,
- }
- timezone = result['ip_time_zone'] or reveal_data['timezone']
- if timezone:
- log_data.update({
- 'timezone': timezone.replace('_', ' ').title(),
- 'timezone_url': reveal_data['timezone_url'],
- })
- return log_data
diff --git a/addons/crm_iap_lead_website/views/crm_reveal_views.xml b/addons/crm_iap_lead_website/views/crm_reveal_views.xml
index 0ac49739e09..32317c529dc 100644
--- a/addons/crm_iap_lead_website/views/crm_reveal_views.xml
+++ b/addons/crm_iap_lead_website/views/crm_reveal_views.xml
@@ -157,7 +157,9 @@
+ parent="crm_iap_lead.crm_menu_lead_generation"
+ name="Visits to Leads"
+ sequence="5"/>