Commit d58b2c80 authored by David Seaward's avatar David Seaward

monitor via woocommerce API and parse with WOO1 parser

parent 2e36dbdd
......@@ -2,22 +2,25 @@
# note that % must be escaped as %%
[settings]
SITE_TITLE=Title
SITE_BYLINE=Example byline
DEBUG=True
ALLOWED_HOSTS=localhost
SITE_TITLE = Title
SITE_BYLINE = Example byline
DEBUG = True
ALLOWED_HOSTS = localhost
STATIC_ROOT = /var/opt/purist/account/static
REGISTRATION_OPEN=True
REG_PERSON_BASE_DN=ou=people,dc=example,dc=com
REG_PERSON_OBJECT_CLASSES=inetOrgPerson,organizationalPerson,person
REG_GROUP_BASE_DN=dc=comms,dc=example,dc=com
REG_GROUP_OBJECT_CLASSES=groupOfNames
AUTH_LDAP_SERVER_URI=ldap://ldap.example.com
AUTH_LDAP_START_TLS=True
AUTH_LDAP_BIND_DN=cn=admin,dc=example,dc=com
AUTH_LDAP_USER_SEARCH_BASE_DN=ou=people,dc=example,dc=com
REGISTRATION_OPEN = True
REG_PERSON_BASE_DN = ou=people,dc=example,dc=com
REG_PERSON_OBJECT_CLASSES = inetOrgPerson,organizationalPerson,person
REG_GROUP_BASE_DN = dc=comms,dc=example,dc=com
REG_GROUP_OBJECT_CLASSES = groupOfNames
AUTH_LDAP_SERVER_URI = ldap://ldap.example.com
AUTH_LDAP_START_TLS = True
AUTH_LDAP_BIND_DN = cn=admin,dc=example,dc=com
AUTH_LDAP_USER_SEARCH_BASE_DN = ou=people,dc=example,dc=com
SQLITE_DB_PATH = /var/opt/purist/account/db.sqlite3
STATICFILES_DIRS = /var/opt/purist/brand
WOO_URL = https://example.com
WOO_WP_API = True
WOO_VERSION = wc/v1
WOO_PRODUCT_LIST = 123,124
WOO1_FIELD_LIST = Existing username,Username
WOO1_EMAIL_SUFFIX = @example.com
import woocommerce
from django.conf import settings
from django.db import models
from django.utils import timezone
......@@ -13,16 +12,6 @@ SERVICE_CHOICES = (
)
def get_wcapi():
return woocommerce.API(
url=settings.WOO_URL,
consumer_key=settings.WOO_CONSUMER_KEY,
consumer_secret=settings.WOO_CONSUMER_SECRET,
wp_api=settings.WOO_WP_API,
version=settings.WOO_VERSION
)
class Limit(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
service = models.CharField(max_length=30, choices=SERVICE_CHOICES)
......@@ -88,6 +77,7 @@ class Limit(models.Model):
return label
class ExternalBundle(models.Model):
parser = models.CharField(max_length=30, choices=EXTERNAL_PARSER_CHOICES)
external_key = models.CharField(max_length=30)
......
from celery import shared_task
from celery.utils.log import get_task_logger
from django.conf import settings
from django.db import transaction
from django.utils import timezone
from woocommerce import API as WOO_API
from .models import ExternalCredit, ExternalBundle, Limit
logger = get_task_logger(__name__)
def get_woo_connection():
return WOO_API(
url=settings.WOO_URL,
consumer_key=settings.WOO_CONSUMER_KEY,
consumer_secret=settings.WOO_CONSUMER_SECRET,
wp_api=settings.WOO_WP_API,
version=settings.WOO_VERSION
)
def get_latest_woo1(connection, product_id):
return connection.get("orders?product=" + str(product_id))
def parse_woo1(json_entry, product_id):
result_list = []
order_name = json_entry["number"]
order_id = json_entry["id"]
for line_item in json_entry["line_items"]:
if line_item["product_id"] == product_id:
item_id = line_item["id"]
product_id = line_item["product_id"]
product_label = line_item["name"]
quantity = line_item["quantity"]
account = "invalid"
for meta_item in line_item["meta"]:
if meta_item["key"] in settings.WOO1_FIELD_LIST: # for example, "Existing username,"
account = meta_item["value"]
if account.count("@") == 0:
account += settings.WOO1_EMAIL_SUFFIX # for example, "@example.com"
elif account.count("@") > 1:
raise Exception("Invalid username: " + account)
elif not account.endswith(settings.WOO1_EMAIL_SUFFIX):
raise Exception("Bad username suffix: " + account)
external_key = str(order_id) + ":" + str(item_id)
external_label = order_name + ":" + str(item_id)
result_list.append({
"parser": "WOO1",
"external_key": external_key,
"label": external_label,
"product_key": product_id,
"product_label": product_label,
"quantity": quantity,
"account": account,
"original_email": "",
"isconverted": False,
})
return result_list
def is_existing_credit(credit):
matching_credits = ExternalCredit.objects.filter(
parser=credit.parser,
external_key=credit.external_key,
)
is_existing = len(matching_credits) > 0
return is_existing
def update_limit_woo1(credit):
# validate credit
if credit.account_name is None or not str.endswith(credit.account_name, settings.WOO1_EMAIL_SUFFIX):
raise Exception("Invalid account name: " + str(credit.account_name))
else:
suffix_len = 0 - len(settings.WOO1_EMAIL_SUFFIX)
username = credit.account_name[:suffix_len]
# get external references (implicit validation that they exist)
external_bundle = ExternalBundle.objects.get(
parser=credit.parser,
external_key=credit.bundle_key,
)
limit = Limit.objects.get(
user__username=username,
service=external_bundle.service,
)
# FIXME: should not simply activate an inactive service
credit_timedelta = timezone.timedelta(days=int(external_bundle.time_credit * credit.quantity))
if limit.is_active:
limit.expiry_date += credit_timedelta
else:
limit.expiry_date = timezone.now() + credit_timedelta
limit.is_active = True
limit.save()
@transaction.atomic
def store_credit_and_update_limit(credit):
try:
if credit.parser == "WOO1":
update_limit_woo1(credit)
else:
raise Exception("Unrecognised parser " + credit.parser)
credit.is_converted = True
except Exception as e:
logger.exception("Skipped adding credit " + credit.parser + ":" + credit.external_key)
finally:
credit.save()
state = "converted" if credit.is_converted else "skipped"
logger.info("Stored " + state + " credit " + credit.parser + ":" + credit.external_key)
@shared_task
def monitor_woo1():
# get API connection to WooCommerce
woo_connection = get_woo_connection()
# get product sales and parse the results
result_list = []
for product_id in settings.WOO_PRODUCT_LIST:
latest_woo1_json = get_latest_woo1(woo_connection, product_id).json()
for json_entry in latest_woo1_json:
try:
result_list.extend(parse_woo1(json_entry, product_id))
except Exception as e:
logger.exception("Skipping JSON entry " + str(json_entry))
# add new results
for result in result_list:
try:
credit = ExternalCredit(
parser=result["parser"],
external_key=result["external_key"],
label=result["label"],
bundle_key=result["product_key"],
bundle_label=result["product_label"],
quantity=result["quantity"],
account_name=result["account"],
additional_data=result["original_email"],
is_converted=False
)
if not is_existing_credit(credit):
store_credit_and_update_limit(credit)
else:
logger.info("Skipped stored result " + str(result))
except Exception as e:
logger.exception("Skipping result " + str(result))
@shared_task
def debug_task(self):
print('Limit monitor')
woo_connection = get_woo_connection()
logger.info("Debug task with " + str(woo_connection) + " completed successfully.")
# from registration_defaults.settings import *
import ldap
from decouple import Config, Csv, RepositoryIni
from django_auth_ldap.config import LDAPSearch
......@@ -34,6 +33,10 @@ ALLOWED_HOSTS = config("ALLOWED_HOSTS", cast=Csv())
INSTALLED_APPS += ["crispy_forms", "django_celery_beat", "ldapregister", "limitmonitor", ]
#
# REGISTRATION APPLICATION
#
REGISTRATION_OPEN = config("REGISTRATION_OPEN", cast=bool)
REG_PERSON_BASE_DN = config("REG_PERSON_BASE_DN")
......@@ -57,7 +60,6 @@ AUTH_PASSWORD_VALIDATORS = [
AUTHENTICATION_BACKENDS = (
'django_auth_ldap.backend.LDAPBackend',
# 'django.contrib.auth.backends.ModelBackend',
)
AUTH_LDAP_SERVER_URI = config("AUTH_LDAP_SERVER_URI")
......@@ -99,12 +101,13 @@ DATABASES = {
DATABASE_ROUTERS = ['ldapdb.router.Router']
STATIC_ROOT = config("STATIC_ROOT")
#
# STATIC AND SITE SETTINGS
#
STATIC_ROOT = config("STATIC_ROOT")
STATICFILES_DIRS = config("STATICFILES_DIRS", cast=Csv())
SITE_TITLE = config("SITE_TITLE")
SITE_BYLINE = config("SITE_BYLINE")
#
......@@ -117,3 +120,12 @@ WOO_VERSION = config("WOO_VERSION")
WOO_CONSUMER_KEY = secret_config("WOO_CONSUMER_KEY")
WOO_CONSUMER_SECRET = secret_config("WOO_CONSUMER_SECRET")
WOO_PRODUCT_LIST = config("WOO_PRODUCT_LIST", cast=Csv(int))
#
# WOO1 PARSER
#
WOO1_EMAIL_SUFFIX = config("WOO1_EMAIL_SUFFIX")
WOO1_FIELD_LIST = config("WOO1_FIELD_LIST", cast=Csv())
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment