<s> from decimal import Decimal <EOL> from sellmo . core import chaining <EOL> from django . utils import six <EOL> from . currency import Currency <EOL> from . exceptions import CurrencyMismatch , PriceComponentOverflow <EOL> from . utils import safe_decimal , merge_amount_dicts <EOL> __all__ = [ '<STR_LIT>' , '<STR_LIT>' ] <EOL> class PriceComponent ( object ) : <EOL> key = None <EOL> verbose_name = None <EOL> extra_fields = None <EOL> """<STR_LIT>""" <EOL> multiplicity = <NUM_LIT:1> <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , key = None , verbose_name = None , multiplicity = None ) : <EOL> self . key = key or self . key <EOL> self . verbose_name = verbose_name or self . verbose_name <EOL> self . multiplicity = multiplicity or self . multiplicity <EOL> self . extra_fields = self . extra_fields or [ ] <EOL> def extract_price ( self , price ) : <EOL> extracted = list ( self . extract ( price ) ) <EOL> if extracted : <EOL> price = Price ( <NUM_LIT:0> , currency = price . currency ) <EOL> for ( amount , extra_values ) in extracted : <EOL> price . amount += amount <EOL> price = self . apply ( price , amount , extra_values ) <EOL> return price <EOL> return None <EOL> def safe_extract ( self , price ) : <EOL> extracted = list ( self . extract ( price ) ) <EOL> if len ( extracted ) > self . multiplicity : <EOL> raise PriceComponentOverflow ( self ) <EOL> if len ( extracted ) < self . multiplicity : <EOL> empty_extra_values = self . empty_extra_values ( ) <EOL> for _ in range ( len ( extracted ) , self . multiplicity ) : <EOL> extracted . append ( ( None , empty_extra_values ) ) <EOL> return extracted <EOL> def extract ( self , price ) : <EOL> """<STR_LIT>""" <EOL> raise NotImplementedError ( ) <EOL> def apply ( self , price , amount , extra_values ) : <EOL> """<STR_LIT>""" <EOL> raise NotImplementedError ( ) <EOL> def construct_extra_model_fields ( self ) : <EOL> """<STR_LIT>""" <EOL> return { } <EOL> def construct_extra_index_fields ( self ) : <EOL> """<STR_LIT>""" <EOL> return { } <EOL> def empty_extra_values ( self ) : <EOL> """<STR_LIT>""" <EOL> return { } <EOL> def prepare_for_index ( self , price , extra_values ) : <EOL> return ( price , extra_values ) <EOL> def prepare_from_index ( self , price , extra_values ) : <EOL> return ( price , extra_values ) <EOL> def prepare_for_model ( self , price , extra_values ) : <EOL> return ( price , extra_values ) <EOL> def prepare_from_model ( self , price , extra_values ) : <EOL> return ( price , extra_values ) <EOL> def __repr__ ( self ) : <EOL> return self . key <EOL> class Price ( object ) : <EOL> COMPONENTS = [ ] <EOL> def sanity_check ( self , other ) : <EOL> if not isinstance ( other , Price ) : <EOL> raise TypeError ( other ) <EOL> if self . currency != other . currency : <EOL> raise CurrencyMismatch ( self , other ) <EOL> @ staticmethod <EOL> @ chaining . define <EOL> def calculate ( currency = None , bare = False , ** kwargs ) : <EOL> if currency is None : <EOL> currency = Currency . get_current ( ) <EOL> yield chaining . update ( currency = currency ) <EOL> with currency . activate ( ) : <EOL> yield chaining . forward <EOL> def __init__ ( self , amount , currency = None , component = None ) : <EOL> amount = safe_decimal ( amount ) <EOL> if currency is None : <EOL> currency = Currency . get_current ( ) <EOL> self . amount = amount <EOL> self . currency = currency <EOL> self . component = component <EOL> components = { } <EOL> if self . component : <EOL> components [ self . component ] = amount <EOL> self . components = components <EOL> def clone ( self , cls = None , clone = None ) : <EOL> if cls is None : <EOL> cls = type ( self ) <EOL> price = cls ( <EOL> self . amount , <EOL> currency = self . currency , <EOL> component = self . component <EOL> ) <EOL> price . components = self . components . copy ( ) <EOL> return price <EOL> def round ( self , digits = <NUM_LIT:2> ) : <EOL> price = self . clone ( ) <EOL> price . amount = safe_decimal ( Decimal ( str ( round ( price . amount , digits ) ) ) ) <EOL> price . components = { <EOL> component : <EOL> safe_decimal ( Decimal ( str ( round ( amount , digits ) ) ) ) <EOL> for component , amount <EOL> in six . iteritems ( price . components ) <EOL> } <EOL> return price <EOL> def __add__ ( self , other ) : <EOL> self . sanity_check ( other ) <EOL> price = self . clone ( ) <EOL> price . amount = safe_decimal ( price . amount + other . amount ) <EOL> price . components = merge_amount_dicts ( <EOL> price . components , <EOL> other . components , <EOL> lambda a , b : safe_decimal ( a + b ) <EOL> ) <EOL> return price <EOL> def __sub__ ( self , other ) : <EOL> self . sanity_check ( other ) <EOL> price = self . clone ( ) <EOL> price . amount = safe_decimal ( price . amount - other . amount ) <EOL> price . components = merge_amount_dicts ( <EOL> price . components , <EOL> other . components , <EOL> lambda a , b : safe_decimal ( a - b ) <EOL> ) <EOL> return price <EOL> def __mul__ ( self , multiplier ) : <EOL> price = self . clone ( ) <EOL> price . amount = safe_decimal ( price . amount * multiplier ) <EOL> price . components = { <EOL> component : safe_decimal ( amount * multiplier ) <EOL> for component , amount in six . iteritems ( price . components ) <EOL> } <EOL> return price <EOL> def __rmul__ ( self , multiplier ) : <EOL> return self . __mul__ ( multiplier ) <EOL> def __div__ ( self , divider ) : <EOL> price = self . clone ( ) <EOL> price . amount /= divider <EOL> price . components = { <EOL> component : safe_decimal ( amount / divider ) <EOL> for component , amount in six . iteritems ( price . components ) <EOL> } <EOL> return price <EOL> def __rdiv__ ( self , divider ) : <EOL> return self . __div__ ( divider ) <EOL> def __neg__ ( self ) : <EOL> price = self . clone ( ) <EOL> price . amount = - price . amount <EOL> price . components = { <EOL> component : safe_decimal ( - amount ) <EOL> for component , amount in six . iteritems ( price . components ) <EOL> } <EOL> return price <EOL> def __eq__ ( self , other ) : <EOL> if not isinstance ( other , Price ) : <EOL> return NotImplemented <EOL> return ( <EOL> self . currency == other . currency and self . amount == other . amount and <EOL> self . component == other . component and <EOL> self . components == other . components <EOL> ) <EOL> def __ne__ ( self , other ) : <EOL> if not isinstance ( other , Price ) : <EOL> return NotImplemented <EOL> return ( <EOL> self . currency != other . currency or self . amount != other . amount or <EOL> self . component != other . component or <EOL> self . components != other . components <EOL> ) <EOL> def __hash__ ( self ) : <EOL> return hash ( <EOL> ( <EOL> self . currency , self . amount , self . component , frozenset ( <EOL> self . components . items ( ) <EOL> ) <EOL> ) <EOL> ) <EOL> def __contains__ ( self , component ) : <EOL> if not isinstance ( component , ( basestring , PriceComponent ) ) : <EOL> raise TypeError ( ) <EOL> elif isinstance ( component , PriceComponent ) : <EOL> return bool ( component . extract_price ( self ) ) <EOL> return component in self . components <EOL> def __getitem__ ( self , component ) : <EOL> if component in self . components : <EOL> return Price ( <EOL> self . components [ component ] , <EOL> currency = self . currency , <EOL> component = component <EOL> ) <EOL> elif isinstance ( component , PriceComponent ) : <EOL> return component . extract_price ( self ) <EOL> raise KeyError ( component ) <EOL> def __setitem__ ( self , component , value ) : <EOL> amount = value <EOL> if isinstance ( amount , Price ) : <EOL> amount = value . amount <EOL> self . components [ component ] = safe_decimal ( amount ) <EOL> def __len__ ( self ) : <EOL> return len ( self . components ) <EOL> def __iter__ ( self ) : <EOL> for component , amount in six . iteritems ( self . components ) : <EOL> yield ( <EOL> component , Price ( <EOL> amount , <EOL> currency = self . currency , <EOL> component = component <EOL> ) <EOL> ) <EOL> def __nonzero__ ( self ) : <EOL> return self . amount != <NUM_LIT:0> <EOL> def __unicode__ ( self ) : <EOL> return self . currency . format ( self . amount ) <EOL> def __repr__ ( self ) : <EOL> return str ( self . amount ) </s>
