from __future__ import annotations import datetime, hashlib, logging, os, pytz, redis, secrets from typing import Dict, List, Optional, Set, Union from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from ..db_sql import redis_lookup_id_random from ..lib_general import * from .common_field_schema import base_fields, default_num_bytes class Order_Cart_Cfg_Base(BaseModel): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) account_name: Optional[str] show_cart: Optional[bool] cart_label: Optional[str] class Order_Cart_Line_Base(BaseModel): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) id_random: Optional[str] = Field( **base_fields['order_cart_line_id_random'], alias='order_cart_line_id_random', default_factory=lambda:secrets.token_urlsafe(default_num_bytes), ) id: Optional[int] = Field( #alias='order_cart_line_id' ) #order_cart_line_id_random: Optional[str] order_cart_id_random: Optional[str] order_cart_id: Optional[int] product_id_random: str product_id: Optional[int] product_type_id: Optional[int] product_type: Optional[str] product_name: Optional[str] product_description: Optional[str] product_unit_price: Optional[int] = Field(0, ge=0, lt=1500000) product_max_quantity: Optional[int] = Field(0, ge=0, lt=150) quantity: int = Field(0, ge=0, lt=150) amount: int = Field(0, ge=0, lt=1500000) recurring: Optional[bool] = False message: Optional[str] notes: Optional[str] created_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) #@validator('order_cart_line_id_random', always=True) def order_cart_line_id_random_copy(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['id_random']: return values['id_random'] return None @validator('id', always=True) def order_cart_line_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['id_random']: log.debug(values['id_random']) return redis_lookup_id_random(record_id_random=values['id_random'], table_name='order_cart_line') return None @validator('order_cart_id', always=True) def order_cart_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['order_cart_id_random']: return redis_lookup_id_random(record_id_random=values['order_cart_id_random'], table_name='order_cart') return None @validator('product_id', always=True) def product_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values.get('product_id_random', None): return redis_lookup_id_random(record_id_random=values['product_id_random'], table_name='product') return None class Config: underscore_attrs_are_private = True fields = base_fields class Order_Cart_DB_Base(BaseModel): log.setLevel(logging.WARNING) log.debug(locals()) id_random: Optional[str] = Field( **base_fields['order_cart_id_random'], alias='order_cart_id_random', default_factory=lambda:secrets.token_urlsafe(default_num_bytes), ) id: Optional[int] = Field( #alias='order_cart_id' ) account_id_random: Optional[str] account_id: Optional[int] # NOTE: This is not really optional person_id_random: Optional[str] person_id: Optional[int] user_id_random: Optional[str] user_id: Optional[int] order_id_random: Optional[str] order_id: Optional[int] total_quantity: Optional[int] = Field(0, ge=0, lt=150) total_amount: Optional[int] = Field(0, ge=0, lt=1500000) notes: Optional[str] _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) #@validator('order_cart_id_random', always=True) def order_cart_id_random_copy(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['id_random']: return values['id_random'] return None @validator('id', always=True) def order_cart_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['id_random']: return redis_lookup_id_random(record_id_random=values['id_random'], table_name='order_cart') return None @validator('account_id', always=True) def account_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['account_id_random']: return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account') return None @validator('person_id', always=True) def person_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['person_id_random']: return redis_lookup_id_random(record_id_random=values['person_id_random'], table_name='person') return None @validator('user_id', always=True) def user_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['user_id_random']: return redis_lookup_id_random(record_id_random=values['user_id_random'], table_name='user') return None @validator('order_id', always=True) def order_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if 'order_id_random' in values and values['order_id_random']: return redis_lookup_id_random(record_id_random=values['order_id_random'], table_name='order') return None class Config: underscore_attrs_are_private = True fields = base_fields class Order_Cart_Base(BaseModel): log.setLevel(logging.WARNING) log.debug(locals()) id_random: Optional[str] = Field( **base_fields['order_cart_id_random'], alias='order_cart_id_random', default_factory=lambda:secrets.token_urlsafe(default_num_bytes), ) id: Optional[int] = Field( #alias='order_cart_id' ) #order_cart_id_random: Optional[str] #order_cart_id: Optional[int] account_id_random: Optional[str] account_id: Optional[int] # NOTE: This is not really optional person_id_random: Optional[str] person_id: Optional[int] user_id_random: Optional[str] user_id: Optional[int] order_id_random: Optional[str] order_id: Optional[int] total_quantity: Optional[int] = Field(0, ge=0, lt=150) total_amount: Optional[int] = Field(0, ge=0, lt=1500000) notes: Optional[str] created_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None order_cart_line_li: List[Order_Cart_Line_Base] = [] cfg: Optional[Order_Cart_Cfg_Base] = Order_Cart_Cfg_Base() _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) #@validator('order_cart_id_random', always=True) def order_cart_id_random_copy(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['id_random']: return values['id_random'] return None @validator('id', always=True) def order_cart_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['id_random']: return redis_lookup_id_random(record_id_random=values['id_random'], table_name='order_cart') return None @validator('account_id', always=True) def account_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['account_id_random']: return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account') return None @validator('person_id', always=True) def person_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['person_id_random']: return redis_lookup_id_random(record_id_random=values['person_id_random'], table_name='person') return None @validator('user_id', always=True) def user_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if values['user_id_random']: return redis_lookup_id_random(record_id_random=values['user_id_random'], table_name='user') return None @validator('order_id', always=True) def order_id_lookup(cls, v, values, **kwargs): log.setLevel(logging.WARNING) log.debug(locals()) if 'order_id_random' in values and values['order_id_random']: return redis_lookup_id_random(record_id_random=values['order_id_random'], table_name='order') return None class Config: underscore_attrs_are_private = True fields = base_fields # ### BEGIN ### API Order Cart Model ### save_order_cart_obj() ### def save_order_cart_obj(order_cart_obj_new=None): log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) if not order_cart_obj_new: return False #log.debug(order_cart_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True)) # Get the current order_cart_line li to compare with what was sent data = {} data['order_cart_id_random'] = order_cart_obj_new.id_random if order_cart_line_rec_li_curr := sql_select(table_name='v_order_cart_line', data=data, rm_id_random=True, as_list=True): #log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL #log.debug(order_cart_line_rec_li_curr) order_cart_line_obj_li_curr = [] for order_cart_line_rec in order_cart_line_rec_li_curr: try: order_cart_line_obj = Order_Cart_Line_Base(**order_cart_line_rec) log.debug(order_cart_line_obj) except ValidationError as e: log.error(e.json()) order_cart_line_obj_li_curr.append(order_cart_line_obj) #log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(order_cart_line_obj_li_curr) else: #log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(order_cart_line_rec_li_curr) order_cart_line_obj_li_curr = [] # Loop through the line list that was sent and compare with what was pulled from the DB # Only insert if a product ID does not match # Only update if a product ID does match for order_cart_line_obj_new in order_cart_obj_new.order_cart_line_li: log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL if not any(order_cart_line_obj_curr.product_id_random == order_cart_line_obj_new.product_id_random for order_cart_line_obj_curr in order_cart_line_obj_li_curr): # Need to append to current list log.info('Need to append to current list') order_cart_line_obj_li_curr.append(order_cart_line_obj_new) else: # Need to update a current list item ... loop through to find log.info('Need to update a current list item ... loop through to find') for index, order_cart_line_obj_curr in enumerate(order_cart_line_obj_li_curr): log.info(index) if order_cart_line_obj_new.product_id_random == order_cart_line_obj_curr.product_id_random: log.info(f'Match: {order_cart_line_obj_curr.product_id_random}') order_cart_line_obj_new.id_random = order_cart_line_obj_curr.id_random order_cart_line_obj_li_curr[index] = order_cart_line_obj_new else: log.info(f'Not a match: {order_cart_line_obj_curr.product_id_random}') # Save merged current and new list to the new order cart object order_cart_obj_new.order_cart_line_li = order_cart_line_obj_li_curr log.debug(order_cart_obj_new) # Final loop through to get the new order totals # Calculate totals order_cart_total_amount = 0 order_cart_total_quantity = 0 for order_cart_line_obj_curr in order_cart_line_obj_li_curr: order_cart_total_amount += order_cart_line_obj_curr.quantity * order_cart_line_obj_curr.amount order_cart_total_quantity += order_cart_line_obj_curr.quantity order_cart_obj_new.total_amount = order_cart_total_amount order_cart_obj_new.total_quantity = order_cart_total_quantity log.debug(order_cart_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_cart_id_random', 'order_cart_line_li', 'cfg', 'created_on', 'updated_on'})) order_cart_obj_data = order_cart_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_cart_id_random', 'order_cart_line_li', 'cfg', 'created_on', 'updated_on'}) # SQL INSERT or UPDATE the order_cart record log.info('SQL INSERT or UPDATE the order_cart record') if order_cart_obj_resp := sql_insert_or_update(sql=None, data=order_cart_obj_data, table_name='order_cart', 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_cart_obj_resp) if isinstance(order_cart_obj_resp, bool) and order_cart_obj_resp: if order_cart_id := order_cart_obj_new.id: pass elif order_cart_id := order_cart_obj_new.id_random: pass elif isinstance(order_cart_obj_resp, int): order_cart_id = order_cart_obj_resp else: return False # Loop through the order_cart_line list to SQL INSERT or UPDATE the records log.info('Loop through the order_cart_line list to SQL INSERT or UPDATE the records') for order_cart_line_obj in order_cart_obj_new.order_cart_line_li: log.debug(f"--- {order_cart_line_obj}") log.debug(order_cart_line_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=False, exclude={})) order_cart_line_obj_data = order_cart_line_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'product_type_id', 'product_type', 'product_name', 'product_description', 'product_unit_price', 'product_max_quantity', 'order_cart_line_id_random', 'created_on', 'updated_on'}) order_cart_line_obj_data['order_cart_id'] = order_cart_id if order_cart_line_obj_resp := sql_insert_or_update(sql=None, data=order_cart_line_obj_data, table_name='order_cart_line', rm_id_random=True, id_random_length=8): pass else: return False log.debug(order_cart_line_obj_resp) return order_cart_id # ### END ### API Order Cart Model ### save_order_cart_obj() ### # ### BEGIN ### API Order Cart Model ### get_order_cart_obj() ### def get_order_cart_obj(order_cart_id=None, inc_order_cart_line_li=None, inc_order_cart_cfg=None): log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) if order_cart_id := redis_lookup_id_random(record_id_random=order_cart_id, table_name='order_cart'): pass else: return False if order_cart_rec := sql_select(table_name='v_order_cart', record_id=order_cart_id): #log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(order_cart_rec) if inc_order_cart_line_li: order_cart_line_data = {} order_cart_line_data['order_cart_id'] = order_cart_id if order_cart_line_rec_li := sql_select(table_name='v_order_cart_line', data=order_cart_line_data, as_list=True): order_cart_rec['order_cart_line_li'] = order_cart_line_rec_li if inc_order_cart_cfg: if order_cart_cfg_rec := sql_select(table_name='v_account_cfg_detail', field_name='account_id', field_value=order_cart_rec.get('account_id', None)): order_cart_rec['cfg'] = order_cart_cfg_rec log.debug(order_cart_rec) else: return False try: order_cart_obj = Order_Cart_Base(**order_cart_rec) log.debug(order_cart_obj) except ValidationError as e: log.error(e.json()) return order_cart_obj # ### END ### API Order Cart Model ### get_order_cart_obj() ###