Hermes is our sales system that manages the connection between TutorCruncher (the system), the callbooker on our
website, and Pipedrive (our current sales CRM).
This system is built using TortoiseORM and FastAPI.
Objects are named different things depending on which system you use:
Hermes | TutorCruncher | Pipedrive | Description |
---|---|---|---|
Company | Cligency | Organisation | A business that is a potential/current customer of TutorCruncher. |
Contact | SR | Person | Someone who works for the Company. |
Pipeline | Pipeline | The sales pipelines | |
Stage | Stage | The stages of the pipelines | |
Deal | Deal | A potential sale with a Company. | |
Meeting | Activity | A meeting with a Contact. |
This project consists of 4 apps:
admin
: Used as an admin interface to deal with configuration callbooker
: Deals with callbacks and availability from the callbooker on the website pipedrive
: Deals with callbacks and data sync to Pipedrive tc2
: Deals with callbacks and data sync to Pipedrivehermes
: Deals with data to do with the entire Hermes systemSince Hermes works with tutorcruncher.com, the TC2 system and Pipedrive, there is quite a lot to set up to get the system working:
Run TC2 locally on port 5000. python manage.py runserver 5000
# Hermes
HERMES_URL = 'https://${your ngrok domain}'
HERMES_API_KEY = ${tc2 api integration private key} # same as tc2_api_key in hermes env vars
Create 5 Admins in TC2, for each of the following:
Navigate to System > Settings > Custom Fields > Add Custom Field
estimated_monthly_income: str (Short Textbox) # estimated monthly income of the Cligency
utm_source: str (Short Textbox) # utm source of the Cligency
utm_campaign: str (Short Textbox) # utm campaign of the Cligency
currency: str (Short Textbox) # currency of the Cligency
referer: str (Short Textbox) # referer of the Cligency
Navigate to ... > Settings > API Integrations > Create API Integration
Hermes
http://localhost:8000/tc2/callback/
this will create a private key, copy this and set it as tc2_api_key
in hermes env vars and HERMES_API_KEY
in tc2 env vars.
Pipedrive is our current sales CRM. We use it to manage our sales pipelines and deals.
Create a pipedrive sandbox account.
Navigate to Profile > Tools and apps > Webhooks > Create 7 new webhooks:
*
deal
, organization
, pipeline
, person
, product
, stage
, user
https://${your ngrok domain}/pipedrive/callback/
None
Navigate to Company Settings > Data Fields
Hint: Look at Extra Tips (at the bottom of README) for a more detailed guide on how to add a new custom field to Pipedrive
[//]: # (has_booked_call )
[//]: # (has_signed_up )
tc2_status: Large text
tc2_cligency_url: Large text
hermes_id: Numerical
bdr_person_id: Numerical
utm_campaign: Large text
utm_source: Large text
estimated_monthly_income: Large text
currency: Large text
support_person_id: Numerical
signup_questionnaire: Large text
website: Large text
paid_invoice_count: Numerical
price_plan: Large text
hermes_id
hermes_id
-> Navigate to Company settings > Manage users > Add User
Now we should setup a couple of users in Pipedrive:
payg / startup sales
enterprise sales
bdr
You can use your email address for each user, i.e sebastian+pdbdrperson@tutorcruncher.com
Get your Pipedrive Owner ID for your Hermes Admins:
Install the dependencies with make install
.
You may need to create the database with make reset-db
.
Then run the server with python -m uvicorn app.main:app --reload
You'll be able to view the admin interface at http://localhost:8000/.
To first create an admin, go to /init
to create an admin user.
Then go to /login
to log in.
# TC2
tc2_api_key={tc2 api integration private key} # can be found in tc2 meta > settings > api
tc2_base_url='http://localhost:5000' # url of your tc2 instance
# Pipedrive
pd_api_key={pipedrive api key} # can be found in pipedrive > settings > personal preferences > api
pd_base_url='https://seb-sandbox2.pipedrive.com' # your pipedrive sandbox url
Create 5 Admins in Hermes, for each of the following:
When creating the admin, ensure that the email
matches their Google account email address, and that the tc2_admin_id
matches the id of the admin in TC2. and that the pd_owner_id
matches the id of the user in Pipedrive.
for support admins, set the pd_owner_id
to 0
Custom fields are used to transfer additional data between TC2 and Pipedrive. 'Custom Fields' are referred to as 'Data Fields' in Pipedrive
The hermes Custom Field object:
machine_name - str: the name of the field in snake_case
name - str: the name of the field
field_type - str: the type of the field (str, int, bool, fk_field)
hermes_field_name - str: the name of the field in the hermes object
tc2_machine_name - str: the name of the field in the tc2 object
pd_field_id - str: the id of the field in pipedrive
linked_object_type - str: the type of object the field is linked to (Company, Contact, Deal, Meeting)
hermes_field_name
and tc2_machine_name
are used to determine where the data is coming from,
if hermes_field_name
is set, then the data is coming from hermes, these will be attribute names on hermes objects, i.e paid_invoice_count
if tc2_machine_name
is set, then the data is coming from TC2 extra attrs
if we want to get and modify a field on a TC2 Object which is not in extra attrs, we need to manually code it into hermes, then use hermes_field_name
to get the data from hermes.
pd_field_id
: inside the objects returned from Pipedrive, the Data fields key is a uuid that is unique to the field, so we need to get the key from the Pipedrive API.
Data fields > Choose the object tab (Lead/deal, Person, Organization, Product), and select the field you want to get the key for, then select the ... and select Copy API key
(this will copy the key to your clipboard
ID | machine_name | name | field_type | hermes_field_name | tc2_machine_name | pd_field_id | linked_object_type |
---|---|---|---|---|---|---|---|
1 | website | Website | str | website | website | xxxxxxxxxxx | Company |
2 | paid_invoice_count | Paid Invoice Count | int | paid_invoice_count | xxxxxxxxxxx | Company | |
3 | tc2_status | TC2 Status | str | tc2_status | xxxxxxxxxxx | Company | |
4 | tc2_cligency_url | TC2 Cligency URL | str | tc2_cligency_url | xxxxxxxxxxx | Company | |
5 | utm_source | UTM Source | str | utm_source | utm_source | xxxxxxxxxxx | Company |
6 | utm_campaign | UTM Campaign | str | utm_campaign | utm_campaign | xxxxxxxxxxx | Company |
7 | estimated_monthly_income | Estimated Monthly Income | str | estimated_income | estimated_monthly_income | xxxxxxxxxxx | Company |
8 | currency | Currency | str | currency | currency | xxxxxxxxxxx | Company |
8 | support_person_id | Support Person ID | fk_field | support_person | xxxxxxxxxxx | Company | |
9 | bdr_person_id | BDR Person ID | fk_field | bdr_person | xxxxxxxxxxx | Company | |
10 | signup_questionnaire | Signup Questionnaire | str | signup_questionnaire | signup_questionnaire | xxxxxxxxxxx | Company |
11 | hermes_id | Hermes ID | fk_field | id | xxxxxxxxxxx | Company | |
12 | hermes_id | Hermes ID | fk_field | id | xxxxxxxxxxx | Contact | |
13 | hermes_id | Hermes ID | fk_field | id | xxxxxxxxxxx | Deal |
xxxxxxxxxxx
with the pd_field_id
from pipedrive, you can get this by selecting the field in pipedrive and selecting the ... then Copy API key
We use ngrok to expose our local hermes server to the internet, so that we can receive webhooks from Pipedrive.
run ngrok on port 8000
ngrok http --${your ngrok domain} 8000
set the HERMES_URL
env var to the ngrok url provided.
HINT: if you create a account with ngrok, it will give you a static url that you can use for the webhooks, that will never expire ;)
PAYG
PAYG - Contacted
then to create a new pipeline click the 'PAYG' dropdown and select 'Add new pipeline'
you should now see all the stages from pipedrive, with their associated pd_stage_id
You should now have 3 pipelines:
PAYG
STARTUP
ENTERPRISE
Now edit each pipeline and set the dft_entry_pipeline_stage
to the stage that the deal should be set to when it is first created in pipedrive. (warning, dropdown is not filtered by pipeline)
in order for the callbooker to work on tutorcruncher.com, you need to set the following env vars:
DEV_MODE=True
in .env
G_PRIVATE_KEY
in .env
to the private key of the google service account G_PRIVATE_KEY_ID
in .env
to the private key id of the google service account Ensure admin has a matching email address to the one in the sales or support team (i.e fionn@tutorcruncher.com)
sales_reps.yml
and support_reps.yml
, hermes_admin_id
to match the sales and support admins ids in hermes.HERMES_URL
= http://localhost:8000
For example we have a new field on the TC2 Cligency called signup_questionnaire
that we want to add to the Organization in Pipedrive.
signup_questionnaire
)Large text
(or whatever type you need)Copy API key
signup_questionnaire
)Signup Questionnaire
)str
)hermes_field_name
or tc2_machine_name
to that of the source data location i.e signup_questionnaire
is coming from TC2 so set tc2_machine_name
to signup_questionnaire
and leave hermes_field_name
blank.pd_field_id
to the field key you got from the pipedrive API (i.e d4db234b06f753a951c0de94456740f270e0f2ed
)Linked Object Type
to the hermes object type that the field is linked to (i.e Company
) Unittests can be run with make test
. You will need to install the test dependencies with make install-dev
first.
testing@tutorcruncher.com
, as superadmins dont trigger actions and webhooks to be sent :exploding_head:Administrator.objects.get(id=68).user
user = _
user.set_password('testing')
user.save(update_fields=['password'])
/start/1
), fill in the details and submitto test with live data, run make restore-from-live
to download and restore the live database to your local machine.
also add your {your ngork url}/pipedrive/callback
to TutorCruncher Pipedrive webhooks,
then you should see all the webhooks and responses in both your local nrork site and any changes you make in pipedrive will be reflected in your local database.
We use aerich
to create and run migrations.
If you have changed a model then you can create migrations with aerich migrate
. A new file will be created in the migrations/models
directory. If you need to run any migrations, use aerich upgrade
.
If you mess up your migrations, you can reset the database with make reset-db
. Delete the migrations folder and run aerich init-db
to recreate the migrations folder and create the initial migration.
More details can be found in the aerich docs.
Create Meta Admins for the sales and support teams in TC2, and heremes, ensuring their tc2_admin_id matches the one in hermes.
python patch.py <patch_name>
tortoise-orm has a shell command that can be used to interact with the database.
first install tortoise-cli
to run the shell, use the following command inside your hermes virtual environment:
tortoise-cli shell
hint1: you will need to import the models you want to use in the shell, i.e from app.models import *
hint2: you can use the await
keyword to run async functions in the shell, i.e await Company.all()
'Inherited Custom Fields' are custom fields that are inherited from the Company model to the Deal model.
machine_name
is the same as the parent field connected to the company model.tc2_machine_name
or hermes_field_name
as they are always coming from the Company Custom Field.fk_field
which should be int