<s> import datetime <EOL> from collections import OrderedDict <EOL> from string import maketrans <EOL> from os import urandom <EOL> from binascii import hexlify <EOL> import pytz <EOL> from sqlalchemy import or_ , and_ <EOL> from sqlalchemy . ext . hybrid import hybrid_property <EOL> from catwatch . lib . util_sqlalchemy import ResourceMixin , AwareDateTime <EOL> from catwatch . lib . money import cents_to_dollars , dollars_to_cents <EOL> from catwatch . extensions import db <EOL> from catwatch . blueprints . billing . gateways . stripecom import Coupon as PaymentCoupon <EOL> class Coupon ( ResourceMixin , db . Model ) : <EOL> DURATION = OrderedDict ( [ <EOL> ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> ] ) <EOL> __tablename__ = '<STR_LIT>' <EOL> id = db . Column ( db . Integer , primary_key = True ) <EOL> code = db . Column ( db . String ( <NUM_LIT:32> ) , index = True , unique = True ) <EOL> duration = db . Column ( db . Enum ( * DURATION , name = '<STR_LIT>' ) , <EOL> index = True , nullable = False , server_default = '<STR_LIT>' ) <EOL> amount_off = db . Column ( db . Integer ( ) ) <EOL> percent_off = db . Column ( db . Integer ( ) ) <EOL> currency = db . Column ( db . String ( <NUM_LIT:8> ) ) <EOL> duration_in_months = db . Column ( db . Integer ( ) ) <EOL> max_redemptions = db . Column ( db . Integer ( ) , index = True ) <EOL> redeem_by = db . Column ( AwareDateTime ( ) , index = True ) <EOL> times_redeemed = db . Column ( db . Integer ( ) , index = True , <EOL> nullable = False , default = <NUM_LIT:0> ) <EOL> valid = db . Column ( db . Boolean ( ) , nullable = False , server_default = '<STR_LIT:1>' ) <EOL> def __init__ ( self , ** kwargs ) : <EOL> if self . code : <EOL> self . code = self . code . upper ( ) <EOL> else : <EOL> self . code = Coupon . random_coupon_code ( ) <EOL> super ( Coupon , self ) . __init__ ( ** kwargs ) <EOL> @ hybrid_property <EOL> def redeemable ( self ) : <EOL> """<STR_LIT>""" <EOL> is_redeemable = or_ ( self . redeem_by . is_ ( None ) , <EOL> self . redeem_by >= datetime . datetime . now ( pytz . utc ) ) <EOL> return and_ ( self . valid , is_redeemable ) <EOL> @ classmethod <EOL> def search ( cls , query ) : <EOL> """<STR_LIT>""" <EOL> if not query : <EOL> return '<STR_LIT>' <EOL> search_query = '<STR_LIT>' . format ( query ) <EOL> return or_ ( Coupon . code . ilike ( search_query ) ) <EOL> @ classmethod <EOL> def random_coupon_code ( cls ) : <EOL> """<STR_LIT>""" <EOL> random_string = hexlify ( urandom ( <NUM_LIT:20> ) ) <EOL> long_code = random_string . translate ( maketrans ( '<STR_LIT>' , <EOL> '<STR_LIT>' ) ) <EOL> short_code = '<STR_LIT>' . format ( long_code [ <NUM_LIT:0> : <NUM_LIT:4> ] , <EOL> long_code [ <NUM_LIT:5> : <NUM_LIT:9> ] , <EOL> long_code [ <NUM_LIT:10> : <NUM_LIT> ] ) <EOL> return short_code <EOL> @ classmethod <EOL> def expire_old_coupons ( cls , compare_datetime = None ) : <EOL> """<STR_LIT>""" <EOL> if compare_datetime is None : <EOL> compare_datetime = datetime . datetime . now ( pytz . utc ) <EOL> condition = Coupon . redeem_by <= compare_datetime <EOL> Coupon . query . filter ( condition ) . update ( { Coupon . valid : not Coupon . valid } ) <EOL> return db . session . commit ( ) <EOL> @ classmethod <EOL> def create ( cls , params ) : <EOL> """<STR_LIT>""" <EOL> payment_params = params <EOL> payment_params [ '<STR_LIT:code>' ] = payment_params [ '<STR_LIT:code>' ] . upper ( ) <EOL> if payment_params . get ( '<STR_LIT>' ) : <EOL> payment_params [ '<STR_LIT>' ] = dollars_to_cents ( payment_params [ '<STR_LIT>' ] ) <EOL> PaymentCoupon . create ( ** payment_params ) <EOL> if '<STR_LIT:id>' in payment_params : <EOL> payment_params [ '<STR_LIT:code>' ] = payment_params [ '<STR_LIT:id>' ] <EOL> del payment_params [ '<STR_LIT:id>' ] <EOL> if '<STR_LIT>' in payment_params : <EOL> if payment_params . get ( '<STR_LIT>' ) is not None : <EOL> params [ '<STR_LIT>' ] = payment_params . get ( '<STR_LIT>' ) . replace ( <EOL> tzinfo = pytz . UTC ) <EOL> coupon = Coupon ( ** payment_params ) <EOL> db . session . add ( coupon ) <EOL> db . session . commit ( ) <EOL> return True <EOL> @ classmethod <EOL> def bulk_delete ( cls , ids ) : <EOL> """<STR_LIT>""" <EOL> delete_count = <NUM_LIT:0> <EOL> for id in ids : <EOL> coupon = Coupon . query . get ( id ) <EOL> if coupon is None : <EOL> continue <EOL> stripe_response = PaymentCoupon . delete ( coupon . code ) <EOL> if stripe_response . get ( '<STR_LIT>' ) : <EOL> coupon . delete ( ) <EOL> delete_count += <NUM_LIT:1> <EOL> return delete_count <EOL> @ classmethod <EOL> def find_by_code ( cls , code ) : <EOL> """<STR_LIT>""" <EOL> formatted_code = code . upper ( ) <EOL> coupon = Coupon . query . filter ( Coupon . redeemable , <EOL> Coupon . code == formatted_code ) . first ( ) <EOL> return coupon <EOL> def redeem ( self ) : <EOL> """<STR_LIT>""" <EOL> self . times_redeemed += <NUM_LIT:1> <EOL> if self . max_redemptions : <EOL> if self . times_redeemed >= self . max_redemptions : <EOL> self . valid = False <EOL> return db . session . commit ( ) <EOL> def serialize ( self ) : <EOL> """<STR_LIT>""" <EOL> params = { <EOL> '<STR_LIT>' : self . duration , <EOL> '<STR_LIT>' : self . duration_in_months , <EOL> } <EOL> if self . amount_off : <EOL> params [ '<STR_LIT>' ] = cents_to_dollars ( self . amount_off ) <EOL> if self . percent_off : <EOL> params [ '<STR_LIT>' ] = self . percent_off , <EOL> return params </s>
