From e466cef774f05a0c2fd99df7b8e714d0da2b9773 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Mon, 28 Mar 2022 12:31:55 +0200 Subject: [PATCH] Basic CRM reporting. --- src/club/civicrm.py | 175 ++++++++++++++++++++++++++++ src/club/models.py | 32 ++++- src/wolnelektury/settings/custom.py | 9 ++ 3 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/club/civicrm.py diff --git a/src/club/civicrm.py b/src/club/civicrm.py new file mode 100644 index 000000000..c44f6f893 --- /dev/null +++ b/src/club/civicrm.py @@ -0,0 +1,175 @@ +from datetime import datetime +import json +from celery.task import task +from django.conf import settings +import requests +import yaml + + +class CiviCRM: + def __init__(self, base, key): + self.base = base + self.api_base = base + 'civicrm/ajax/api4/' + self.key = key + self.enabled = bool(self.base and self.key) + + def request(self, resource, method, params): + if not self.enabled: + return + + response = requests.post( + self.api_base + f'{resource}/{method}', + params={ + 'params': json.dumps(params), + 'api_key': self.key + }, + ) + d = response.json() + return d + + def create_or_update_contact(self, email, key): + contact_id = self.get_contact_id(email) + if contact_id is None: + contact_id = self.create_contact(email, key) + else: + self.update_contact(contact_id, key) + return contact_id + + def get_contact_id(self, email): + result = self.request( + 'Contact', + 'get', + { + "join": [["Email AS email", "LEFT"]], + "where":[["email.email", "=", email]], + "limit":1, + "debug":True + } + )['values'] + if result: + return result[0]['id'] + + def create_contact(self, email, key): + result = self.request( + 'Contact', + 'create', + { + 'values': { + 'WL.TPWL_key': key, + }, + 'chain': { + 'email': [ + 'Email', + 'create', + { + 'values': { + 'email': email, + 'contact_id': '$id' + } + } + ] + } + } + ) + return result[0]['id'] + + def update_contact(self, contact_id, key): + return self.request( + 'Contact', + 'update', + { + 'values': { + 'WL.TPWL_key': key, + }, + 'where': [ + ['id', '=', contact_id] + ] + } + ) + + + def report_activity(self, email, tpwl_key, key, name, datetime, details): + contact_id = self.create_or_update_contact(email, tpwl_key) + + activity_id = self.get_activity_id(key) + if activity_id is None: + self.create_activity( + contact_id, + key, + name, + datetime, + details + ) + else: + self.update_activity( + activity_id, + contact_id, + name, + datetime, + details + ) + + def get_activity_id(self, key): + result = self.request( + 'Activity', + 'get', + { + 'where': [ + ['subject', '=', key], + ] + } + )['values'] + if result: + return result[0]['id'] + + def create_activity(self, contact_id, key, name, date_time, details): + detail_str = yaml.dump(details) + return self.request( + 'Activity', + 'create', + { + 'values': { + 'source_contact_id': contact_id, + 'activity_type_id:name': name, + 'status_id:name': 'Completed', + 'activity_date_time': date_time.isoformat() if date_time else '', + 'details' : detail_str, + 'subject': key, + }, + 'debug': True, + } + ) + + def update_activity(self, activity_id, contact_id, name, date_time, details): + detail_str = yaml.dump(details) + + self.request( + 'Activity', + 'update', + { + 'values': { + 'source_contact_id': contact_id, + 'activity_type_id:name': name, + 'status_id:name': 'Completed', + 'activity_date_time': date_time.isoformat(), + 'details' : detail_str, + }, + 'where': [ + ['id', '=', activity_id] + ] + } + ) + + #do we create a civicontribution? + + +civicrm = CiviCRM( + settings.CIVICRM_BASE, + settings.CIVICRM_KEY, +) + +@task(ignore_result=True) +def report_activity(*args, **kwargs): + civicrm.report_activity(*args, **kwargs) + + diff --git a/src/club/models.py b/src/club/models.py index a0722d38e..548423a1b 100644 --- a/src/club/models.py +++ b/src/club/models.py @@ -19,6 +19,7 @@ from messaging.states import Level from reporting.utils import render_to_pdf from .payment_methods import methods from .payu import models as payu_models +from .civicrm import report_activity from . import utils @@ -293,7 +294,36 @@ class PayUOrder(payu_models.Order): def status_updated(self): if self.status == 'COMPLETED': self.schedule.set_payed() - + self.report_activity() + + @property + def updated_at(self): + try: + return self.notification_set.all().order_by('-received_at')[0].received_at + except IndexError: + return None + + def report_activity(self): + if self.status not in ['COMPLETED', 'CANCELED', 'REJECTED']: + return + + if self.status != 'COMPLETED': + name = settings.CIVICRM_ACTIVITIES['Failed contribution'] + elif self.is_recurring(): + name = settings.CIVICRM_ACTIVITIES['Recurring contribution'] + else: + name = settings.CIVICRM_ACTIVITIES['Contribution'] + + report_activity.delay( + self.schedule.email, + self.schedule.key, + f'payu:{self.id}', + name, + self.updated_at, + { + 'kwota': self.schedule.amount, + } + ) @classmethod def send_receipt(cls, email, year): diff --git a/src/wolnelektury/settings/custom.py b/src/wolnelektury/settings/custom.py index 68a2153a8..814289b50 100644 --- a/src/wolnelektury/settings/custom.py +++ b/src/wolnelektury/settings/custom.py @@ -48,3 +48,12 @@ VARIANTS = { } EPUB_FUNDRAISING = [] + +CIVICRM_BASE = None +CIVICRM_KEY = None + +CIVICRM_ACTIVITIES = { + 'Contribution': 'Wpłata', + 'Recurring contribution': 'Wpłata cykliczna', + 'Failed contribution': 'Nieudana wpłata', +} -- 2.20.1