Files
OSIT-AE-API-FastAPI/app/methods/membership_person_methods.py

528 lines
26 KiB
Python

from __future__ import annotations
import datetime
from typing import Dict, List, Optional, Set, Union
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
from app.lib_general import log, logging
from app.db_sql import redis_lookup_id_random, sql_insert_or_update, sql_select
from app.methods.membership_cfg_methods import load_membership_cfg_obj
from app.methods.membership_group_methods import get_membership_group_rec_list, load_membership_group_obj
from app.methods.membership_group_person_methods import get_membership_group_person_rec_list, load_membership_group_person_obj
from app.methods.membership_person_profile_methods import get_membership_person_profile_rec_list, load_membership_person_profile_obj
from app.methods.person_methods import load_person_obj
from app.methods.product_methods import load_product_obj
from app.methods.user_methods import load_user_obj
from app.models.membership_person_models import Membership_Person_Base
# ### BEGIN ### API Membership Person Methods ### load_membership_person_obj() ###
def load_membership_person_obj(
membership_person_id:int|str,
limit: int = 1000,
by_alias: bool = True,
exclude_unset: bool = True,
model_as_dict: bool = False,
enabled: str = 'enabled', # enabled, disabled, all
inc_address: bool = False,
inc_contact: bool = False,
inc_membership_cfg: bool = False,
inc_membership_group: bool = False, # Their primary membership group
inc_membership_group_list: bool = False, # The list of membership groups the person is a part of
inc_membership_group_person: bool = False, # The person information for their primary membership group
inc_membership_group_person_list: bool = False, # The person information for all of their membership groups
inc_membership_person_profile: bool = False,
inc_membership_person_profile_cust: bool = False, # Extended profile?
inc_membership_type: bool = False, # Their primary membership type
inc_membership_type_list: bool = False, # The list of membership types the person is a part of
inc_membership_type_person: bool = False, # The person information for their primary membership type
inc_membership_type_person_list: bool = False, # The person information for all of their membership types
# inc_order: bool = False,
inc_organization: bool = False,
inc_person: bool = False,
inc_product: bool = False, # The product the person actually purchased for a member_type or member_group
inc_product_list: bool = False, # The list of products that give access to a member_type or member_group
inc_user: bool = False,
) -> Membership_Person_Base:
log.setLevel(logging.WARING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if membership_person_id := redis_lookup_id_random(record_id_random=membership_person_id, table_name='membership_person'): pass
else: return False
if membership_person_rec := sql_select(table_name='v_membership_person', record_id=membership_person_id): pass
else: return False
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(membership_person_rec)
try:
membership_person_obj = Membership_Person_Base(**membership_person_rec)
log.debug(membership_person_obj)
except ValidationError as e:
log.error(e.json())
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(membership_person_obj)
# Updated 2021-06-24
if inc_membership_cfg:
if membership_cfg_obj_result := load_membership_cfg_obj(
account_id = membership_person_rec.get('account_id', None),
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
):
membership_person_obj.membership_cfg = membership_cfg_obj_result
else: membership_person_obj.membership_cfg = None
if inc_membership_group: pass # The primary membership group the person is a part of. Not used at this time.
# Updated 2021-07-09
if inc_membership_group_list: # The list of groups the member is a part of
if membership_group_rec_list_result := get_membership_group_rec_list(
# for_obj_type = 'membership_person',
# for_obj_id = membership_person_id,
membership_person_id = membership_person_id,
limit = limit,
enabled = enabled,
):
membership_group_result_list = []
for membership_group_rec in membership_group_rec_list_result:
if load_membership_group_result := load_membership_group_obj(
membership_group_id = membership_group_rec.get('membership_group_id', None),
limit = limit,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
enabled = enabled,
# inc_membership_group_list = inc_membership_group_list,
# inc_membership_person_profile = inc_membership_person_profile,
# inc_organization = inc_organization,
# inc_person = inc_person,
# inc_product = inc_product,
# inc_product_list = inc_product_list,
# inc_user = inc_user,
):
membership_group_result_list.append(load_membership_group_result)
else: membership_group_result_list.append(None)
membership_person_obj.membership_group_list = membership_group_result_list
else: membership_person_obj.membership_group_list = []
# Updated 2021-07-09
if inc_membership_group_person_list: # The person information for the list of groups the member is a part of
if membership_group_person_rec_list_result := get_membership_group_person_rec_list(
for_obj_type = 'membership_person',
for_obj_id = membership_person_id,
# membership_person_id = membership_person_id,
limit = limit,
enabled = enabled,
):
membership_group_person_result_list = []
for membership_group_person_rec in membership_group_person_rec_list_result:
if load_membership_group_person_result := load_membership_group_person_obj(
membership_group_person_id = membership_group_person_rec.get('membership_group_person_id', None),
limit = limit,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
enabled = enabled,
# inc_membership_group_person_list = inc_membership_group_person_list,
# inc_membership_person_profile = inc_membership_person_profile,
# inc_organization = inc_organization,
# inc_person = inc_person,
inc_product = inc_product,
# inc_product_list = inc_product_list,
# inc_user = inc_user,
):
membership_group_person_result_list.append(load_membership_group_person_result)
else: membership_group_person_result_list.append(None)
membership_person_obj.membership_group_person_list = membership_group_person_result_list
else: membership_person_obj.membership_group_person_list = []
# Updated 2021-06-21
if inc_membership_person_profile:
membership_person_profile_id = membership_person_rec.get('membership_person_profile_id', None)
log.debug(membership_person_profile_id)
if membership_person_profile_result := load_membership_person_profile_obj(
membership_person_profile_id = membership_person_profile_id,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
inc_address = inc_address,
inc_contact = inc_contact,
# inc_membership = inc_membership,
# inc_membership_cfg = inc_membership_cfg,
inc_organization = inc_organization,
):
membership_person_obj.membership_person_profile = membership_person_profile_result
else: membership_person_obj.membership_person_profile = None
log.debug(membership_person_profile_result)
# Updated 2021-07-09
if inc_membership_type: # The primary membership type for the person
from app.methods.membership_type_methods import load_membership_type_obj
membership_type_id = membership_person_rec.get('membership_type_id', None)
log.debug(membership_type_id)
if membership_type_result := load_membership_type_obj(
membership_type_id = membership_type_id,
limit = limit,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
enabled = enabled,
# inc_address = inc_address,
# inc_contact = inc_contact,
# inc_membership = inc_membership,
# inc_membership_cfg = inc_membership_cfg,
# inc_organization = inc_organization,
inc_product_list = inc_product_list,
):
membership_person_obj.membership_type = membership_type_result
else: membership_person_obj.membership_type = None
log.debug(membership_type_result)
if inc_membership_type_list: pass # All of the membership types the person is a part of
# Updated 2021-07-09
if inc_membership_type_person: # The primary membership type person information for the person
from app.methods.membership_type_person_methods import load_membership_type_person_obj
membership_type_person_id = membership_person_rec.get('membership_type_person_id', None)
log.debug(membership_type_person_id)
if membership_type_person_result := load_membership_type_person_obj(
membership_type_person_id = membership_type_person_id,
limit = limit,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
enabled = enabled,
inc_membership_cfg = inc_membership_cfg,
inc_membership_type = inc_membership_type,
inc_product = inc_product,
):
membership_person_obj.membership_type_person = membership_type_person_result
else: membership_person_obj.membership_type_person = None
log.debug(membership_type_person_result)
if inc_membership_type_person_list: pass # All of the membership type person records for a person
# Updated 2021-06-18
if inc_person:
person_id = membership_person_rec.get('person_id', None)
log.debug(person_id)
if person_result := load_person_obj(
person_id = person_id,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
inc_address = inc_address,
inc_contact = inc_contact,
# inc_organization = inc_organization,
# inc_user = inc_user,
):
membership_person_obj.person = person_result
else: membership_person_obj.person = None
log.debug(person_result)
# Updated 2021-06-24
if inc_product:
product_id = membership_person_rec.get('product_id', None)
log.debug(product_id)
if product_result := load_product_obj(
product_id = product_id,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
):
membership_person_obj.product = product_result
else: membership_person_obj.product = None
log.debug(product_result)
# Updated 2021-06-18
if inc_user:
user_id = membership_person_rec.get('user_id', None)
if user_result := load_user_obj(
user_id = user_id,
by_alias = by_alias,
exclude_unset = exclude_unset,
model_as_dict = model_as_dict,
# inc_address = inc_address,
# inc_contact = inc_contact,
# inc_organization = inc_organization,
# inc_person = inc_person,
):
membership_person_obj.user = user_result
else: membership_person_obj.user = None
log.debug(user_result)
if model_as_dict:
return membership_person_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
else:
return membership_person_obj
# ### END ### API Membership Person Methods ### load_membership_person_obj() ###
# ### BEGIN ### API Membership Person Methods ### get_membership_person_rec_list() ###
def get_membership_person_rec_list(
for_obj_type: str,
for_obj_id: str,
limit: int = 1000,
enabled: str = 'enabled', # enabled, disabled, all
) -> list|bool:
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
else: return False
data = {}
data[f'{for_obj_type}_id'] = for_obj_id
allowed_forign_key_li = ['account', 'membership_type', 'person', 'user']
if for_obj_type in allowed_forign_key_li:
log.info(f'Query using forign key: {for_obj_type} {for_obj_id}')
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
if enabled in ['enabled', 'disabled', 'all']:
if enabled == 'enabled':
data['enable'] = True
sql_enabled = f'AND `tbl`.enable = :enable'
elif enabled == 'disabled':
data['enable'] = False
sql_enabled = f'AND `tbl`.enable = :enable'
elif enabled == 'all':
sql_enabled = ''
if limit:
data['limit'] = limit
sql_limit = f'LIMIT :limit'
else:
sql_limit = ''
sql = f"""
SELECT `tbl`.id AS 'membership_person_id', `tbl`.id_random AS 'membership_person_id_random'
FROM `membership_person` AS `tbl`
WHERE
{sql_obj_type_id}
{sql_enabled}
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
{sql_limit};
"""
elif for_obj_type == 'unknown':
log.info(f'Query using joined table: {for_obj_type} {for_obj_id}')
# sql_obj_type_id = f'`membership_person`.{for_obj_type}_id = :{for_obj_type}_id'
# if enabled in ['enabled', 'disabled', 'all']:
# if enabled == 'enabled':
# data['enable'] = True
# sql_enabled = f'AND `membership_person`.enable = :enable'
# elif enabled == 'disabled':
# data['enable'] = False
# sql_enabled = f'AND `membership_person`.enable = :enable'
# elif enabled == 'all':
# sql_enabled = ''
# if limit:
# data['limit'] = limit
# sql_limit = f'LIMIT :limit'
# else:
# sql_limit = ''
# sql = f"""
# SELECT `membership_person`.id AS 'membership_type_id', `membership_person`.id_random AS 'membership_type_id_random'
# FROM `membership_person`
# INNER JOIN membership_type ON membership_person.membership_type_id = membership_type.id
# WHERE
# {sql_obj_type_id}
# {sql_enabled}
# ORDER BY `membership_person`.created_on DESC, `membership_person`.updated_on DESC
# {sql_limit};
# """
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql)
# sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
# if enabled in ['enabled', 'disabled', 'all']:
# if enabled == 'enabled':
# data['enable'] = True
# sql_enabled = f'AND `tbl`.enable = :enable'
# elif enabled == 'disabled':
# data['enable'] = False
# sql_enabled = f'AND `tbl`.enable = :enable'
# elif enabled == 'all':
# sql_enabled = ''
# if limit:
# data['limit'] = limit
# sql_limit = f'LIMIT :limit'
# else:
# sql_limit = ''
# sql = f"""
# SELECT `tbl`.id AS 'membership_person_id', `tbl`.id_random AS 'membership_person_id_random'
# FROM `membership_person` AS `tbl`
# WHERE
# {sql_obj_type_id}
# {sql_enabled}
# ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
# {sql_limit};
# """
if membership_person_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
membership_person_rec_li = membership_person_rec_li_result
else:
membership_person_rec_li = []
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(membership_person_rec_li_result)
return membership_person_rec_li
# ### END ### API Membership Person Methods ### get_membership_person_rec_list() ###
# ### BEGIN ### API Membership Person Methods ### save_membership_person_obj() ###
def save_membership_person_obj(order_obj_new:Membership_Person_Base=None):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if not order_obj_new:
return False
log.debug(order_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True))
order_line_obj_li_curr = [] # Initialize to store order_line list
if order_obj_new.id_random:
log.info(f'An order.id {order_obj_new.id} or order.id_random {order_obj_new.id_random} was included. We can update an existing order.')
log.info(f'Get the current order_line list to compare with what was sent...')
data = {}
data['order_id_random'] = order_obj_new.id_random
if order_line_rec_li_curr := sql_select(table_name='v_order_line', data=data, rm_id_random=True, as_list=True):
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(order_line_rec_li_curr)
for order_line_rec in order_line_rec_li_curr:
try:
order_line_obj = Order_Line_Base(**order_line_rec)
log.debug(order_line_obj)
except ValidationError as e:
log.error(e.json())
order_line_obj_li_curr.append(order_line_obj)
else:
log.info(f'No order_line records were found')
elif order_obj_new.account_id_random and (order_obj_new.person_id_random or order_obj_new.user_id_random):
log.info(f'An account.id_random {order_obj_new.account_id_random} was passed. And either a person.id_random {order_obj_new.person_id_random} or user.id_random {order_obj_new.user_id_random} was passed. We can create a new order.')
# Because there was not an order ID, assume there are no order lines yet. So no look up.
else:
log.info('Either an order ID is required to update an order or an account ID along with a person ID or user ID is required to create an order.')
return False
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(order_line_obj_li_curr)
if repl_order_line_list: # This will remove any order line list items not sent with the new order information.
log.info('Removing any order line list items not sent with the new order information...')
for index, order_line_obj_curr in enumerate(order_line_obj_li_curr):
log.info(f'Current: order line ID={order_line_obj_curr.id_random} and product ID= {order_line_obj_curr.product_id_random}')
matched_product_id = False
for order_line_obj_new in order_obj_new.order_line_list:
log.debug(f'Checking new: product ID={order_line_obj_new.product_id_random}')
if order_line_obj_curr.product_id_random == order_line_obj_new.product_id_random:
matched_product_id = True
log.debug(f'Matched: product ID={order_line_obj_new.product_id_random}')
break
else:
log.debug(f'No match: product ID={order_line_obj_new.product_id_random}')
if not matched_product_id: # Was not found in the new order line list sent
log.info(f'Current order line product ID did not match any of the new list. DELETE order line ID {order_line_obj_curr.id_random} with product ID {order_line_obj_curr.product_id_random}')
if order_line_del_result := sql_delete(table_name='order_line', record_id_random=order_line_obj_curr.id_random):
log.info(f'Deleted record and now pop the current list item {index}...')
order_line_obj_li_curr.pop(index)
else:
log.info(f'Current order line product ID matched. Keeping order line ID {order_line_obj_curr.id_random} with product ID {order_line_obj_curr.product_id_random}')
# NOTE: That this current order line item will be updated below.
log.debug(order_line_obj_li_curr)
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.info('Loop through the line list that was sent and compare with what was pulled from the DB')
# Loop through the new line list that was sent and compare with the current line list that was pulled from the DB
# Only insert if a product ID does not match
# Only update if a product ID does match
for order_line_obj_new in order_obj_new.order_line_list:
log.info(f'New: order line ID={order_line_obj_new.id_random} and product ID= {order_line_obj_new.product_id_random}')
matched_product_id = False
for index, order_line_obj_curr in enumerate(order_line_obj_li_curr):
log.debug(f'Checking current: product ID={order_line_obj_curr.product_id_random}')
if order_line_obj_new.product_id_random == order_line_obj_curr.product_id_random:
matched_product_id = True
log.debug(f'Matched: product ID={order_line_obj_curr.product_id_random}')
log.info(f'Updating the current line item with the new line item.')
order_line_obj_new.id_random = order_line_obj_curr.id_random
order_line_obj_new.id = order_line_obj_curr.id
order_line_obj_li_curr[index] = order_line_obj_new
break
else:
log.debug(f'No match: product ID={order_line_obj_curr.product_id_random}')
if not matched_product_id: # Was not found in the current order line list that was pulled from the DB
log.info(f'New order line product ID did not match any of the current list. Append order line ID {order_line_obj_new.id_random} with product ID {order_line_obj_new.product_id_random}')
log.info('Append to current list...')
order_line_obj_li_curr.append(order_line_obj_new) # These will be inserted/updated below
# Save merged current and new list to the new order object
order_obj_new.order_line_list = order_line_obj_li_curr
log.debug(order_obj_new)
# Final loop through to get the new order totals
# Calculate totals
order_total_amount:int = 0
order_total_quantity:int = 0
for order_line_obj_new in order_obj_new.order_line_list:
order_total_amount += order_line_obj_new.quantity * order_line_obj_new.amount
order_total_quantity += order_line_obj_new.quantity
order_obj_new.total_bill = order_total_amount # "amount" is used by order_cart and Stripe
order_obj_new.total_quantity = order_total_quantity
order_obj_new.balance = order_total_amount - order_obj_new.total_paid
log.debug(order_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_line_list', 'cfg', 'created_on', 'updated_on'}))
order_obj_data = order_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_line_list', 'cfg', 'created_on', 'updated_on'})
# SQL INSERT or UPDATE the order record
log.info('SQL INSERT or UPDATE the order record')
if order_obj_resp := sql_insert_or_update(data=order_obj_data, table_name='order', rm_id_random=True, id_random_length=8): pass
else: return False
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(order_obj_resp)
if isinstance(order_obj_resp, bool) and order_obj_resp:
if order_id := order_obj_new.id: pass
elif order_id := order_obj_new.id_random: pass
elif isinstance(order_obj_resp, int):
order_id = order_obj_resp
else:
return False
log.debug(f'Order ID={order_id}')
# Loop through the order_line list to SQL INSERT or UPDATE the records
log.info('Loop through the order_line list to SQL INSERT or UPDATE the records')
for order_line_obj_new in order_obj_new.order_line_list:
log.info(f"New order_line: order_line_id_random={order_line_obj_new.id_random}; product_id_random={order_line_obj_new.product_id_random}")
log.debug(order_line_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=False, exclude={'order_line_id_random', 'product_type_id', 'product_type', 'created_on', 'updated_on'}))
order_line_obj_data = order_line_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_line_id_random', 'product_type_id', 'product_type', 'created_on', 'updated_on'})
order_line_obj_data['order_id'] = order_id
if order_line_obj_resp := sql_insert_or_update(sql=None, data=order_line_obj_data, table_name='order_line', rm_id_random=True, id_random_length=8): pass
else: return False
log.debug(order_line_obj_resp)
return order_id
# ### END ### API Membership Person Methods ### save_membership_person_obj() ###