def delete_campaign(link, campaign): PromotionWeights.delete(link, campaign) void_campaign(link, campaign, reason='deleted_campaign') campaign.delete() PromotionLog.add(link, 'deleted campaign %s' % campaign._id) hooks.get_hook('promote.delete_campaign').call(link=link, campaign=campaign)
def charge_campaign(link, campaign): if charged_or_not_needed(campaign): return user = Account._byID(link.author_id) success, reason = authorize.charge_transaction(user, campaign.trans_id, campaign._id) if not success: if reason == authorize.TRANSACTION_NOT_FOUND: # authorization hold has expired original_trans_id = campaign.trans_id campaign.trans_id = NO_TRANSACTION campaign._commit() text = ('voided expired transaction for %s: (trans_id: %d)' % (campaign, original_trans_id)) PromotionLog.add(link, text) return hooks.get_hook('promote.edit_campaign').call(link=link, campaign=campaign) if not is_promoted(link): update_promote_status(link, PROMOTE_STATUS.pending) emailer.queue_promo(link, campaign.total_budget_dollars, campaign.trans_id) text = ('auth charge for campaign %s, trans_id: %d' % (campaign._id, campaign.trans_id)) PromotionLog.add(link, text)
def terminate_campaign(link, campaign): if not is_live_promo(link, campaign): return now = promo_datetime_now() original_end = campaign.end_date dates = [campaign.start_date, now] # NOTE: this will delete PromotionWeights after and including now.date() edit_campaign( link=link, campaign=campaign, dates=dates, target=campaign.target, frequency_cap=campaign.frequency_cap, priority=campaign.priority, location=campaign.location, total_budget_pennies=campaign.total_budget_pennies, cost_basis=campaign.cost_basis, bid_pennies=campaign.bid_pennies, ) campaigns = list(PromoCampaign._by_link(link._id)) is_live = any( is_live_promo(link, camp) for camp in campaigns if camp._id != campaign._id) if not is_live: update_promote_status(link, PROMOTE_STATUS.finished) all_live_promo_srnames(_update=True) msg = 'terminated campaign %s (original end %s)' % (campaign._id, original_end.date()) PromotionLog.add(link, msg)
def new_promotion(is_self, title, content, author, ip): """ Creates a new promotion with the provided title, etc, and sets it status to be 'unpaid'. """ sr = Subverbify._byID(Subverbify.get_promote_srid()) l = Link._submit( is_self=is_self, title=title, content=content, author=author, sr=sr, ip=ip, ) l.promoted = True l.disable_comments = False l.sendreplies = True PromotionLog.add(l, 'promotion created') update_promote_status(l, PROMOTE_STATUS.unpaid) # the user has posted a promotion, so enable the promote menu unless # they have already opted out if author.pref_show_promote is not False: author.pref_show_promote = True author._commit() # notify of new promo emailer.new_promo(l) return l
def refund_campaign(link, camp, refund_amount, billable_amount, billable_impressions): owner = Account._byID(camp.owner_id, data=True) success, reason = authorize.refund_transaction(owner, camp.trans_id, camp._id, refund_amount) if not success: text = ('%s $%s refund failed' % (camp, refund_amount)) PromotionLog.add(link, text) g.log.debug(text + ' (reason: %s)' % reason) return False if billable_impressions: text = ('%s completed with $%s billable (%s impressions @ $%s).' ' %s refunded.' % (camp, billable_amount, billable_impressions, camp.bid_pennies / 100., refund_amount)) else: text = ('%s completed with $%s billable. %s refunded' % (camp, billable_amount, refund_amount)) PromotionLog.add(link, text) camp.refund_amount = refund_amount camp._commit() queries.unset_underdelivered_campaigns(camp) emailer.refunded_promo(link) return True
def toggle_pause_campaign(link, campaign, should_pause): campaign.paused = should_pause campaign._commit() action = 'paused' if should_pause else 'resumed' PromotionLog.add(link, '%s campaign %s' % (action, campaign._id)) hooks.get_hook('promote.edit_campaign').call(link=link, campaign=campaign)
def review_fraud(link, is_fraud): link.fraud = is_fraud link._commit() PromotionLog.add( link, "marked as fraud" if is_fraud else "resolved as not fraud") queries.unset_payment_flagged_link(link) if is_fraud: reject_promotion(link, "fraud", notify_why=False) hooks.get_hook("promote.fraud_identified").call(link=link, sponsor=c.user)
def finalize_completed_campaigns(daysago=1): # PromoCampaign.end_date is utc datetime with year, month, day only now = datetime.datetime.now(g.tz) date = now - datetime.timedelta(days=daysago) date = date.replace(hour=0, minute=0, second=0, microsecond=0) q = PromoCampaign._query( PromoCampaign.c.end_date == date, # exclude no transaction PromoCampaign.c.trans_id != NO_TRANSACTION, data=True) # filter out freebies campaigns = filter(lambda camp: camp.trans_id > NO_TRANSACTION, q) if not campaigns: return # check that traffic is up to date earliest_campaign = min(campaigns, key=lambda camp: camp.start_date) start, end = get_total_run(earliest_campaign) missing_traffic = traffic.get_missing_traffic(start.replace(tzinfo=None), date.replace(tzinfo=None)) if missing_traffic: raise ValueError("Can't finalize campaigns finished on %s." "Missing traffic from %s" % (date, missing_traffic)) links = Link._byID([camp.link_id for camp in campaigns], data=True) underdelivered_campaigns = [] for camp in campaigns: if hasattr(camp, 'refund_amount'): continue link = links[camp.link_id] billable_impressions = get_billable_impressions(camp) billable_amount = get_billable_amount(camp, billable_impressions) if billable_amount >= camp.total_budget_pennies: if hasattr(camp, 'cpm'): text = '%s completed with $%s billable (%s impressions @ $%s).' text %= (camp, billable_amount, billable_impressions, camp.bid_dollars) else: text = '%s completed with $%s billable (pre-CPM).' text %= (camp, billable_amount) PromotionLog.add(link, text) camp.refund_amount = 0. camp._commit() elif charged_or_not_needed(camp): underdelivered_campaigns.append(camp) if underdelivered_campaigns: queries.set_underdelivered_campaigns(underdelivered_campaigns)
def flag_payment(link, reason): # already determined to be fraud or already flagged for that reason. if link.fraud or reason in link.payment_flagged_reason: return if link.payment_flagged_reason: link.payment_flagged_reason += (", %s" % reason) else: link.payment_flagged_reason = reason link._commit() PromotionLog.add(link, "payment flagged: %s" % reason) queries.set_payment_flagged_link(link)
def reject_promotion(link, reason=None, notify_why=True): if is_rejected(link): return was_live = is_promoted(link) update_promote_status(link, PROMOTE_STATUS.rejected) if reason: PromotionLog.add(link, "rejected: %s" % reason) # Send a rejection email (unless the advertiser requested the reject) if not c.user or c.user._id != link.author_id: emailer.reject_promo(link, reason=(reason if notify_why else None)) if was_live: all_live_promo_srnames(_update=True)
def new_campaign(link, dates, target, frequency_cap, priority, location, platform, mobile_os, ios_devices, ios_version_range, android_devices, android_version_range, total_budget_pennies, cost_basis, bid_pennies): campaign = PromoCampaign.create( link, target, dates[0], dates[1], frequency_cap, priority, location, platform, mobile_os, ios_devices, ios_version_range, android_devices, android_version_range, total_budget_pennies, cost_basis, bid_pennies) PromotionWeights.add(link, campaign) PromotionLog.add(link, 'campaign %s created' % campaign._id) if not campaign.is_house: author = Account._byID(link.author_id, data=True) if getattr(author, "complimentary_promos", False): free_campaign(link, campaign, c.user) hooks.get_hook('promote.new_campaign').call(link=link, campaign=campaign) return campaign
def void_campaign(link, campaign, reason): transactions = get_transactions(link, [campaign]) bid_record = transactions.get(campaign._id) if bid_record: a = Account._byID(link.author_id) authorize.void_transaction(a, bid_record.transaction, campaign._id) campaign.trans_id = NO_TRANSACTION campaign._commit() text = ('voided transaction for %s: (trans_id: %d)' % (campaign, bid_record.transaction)) PromotionLog.add(link, text) if bid_record.transaction > 0: # notify the user that the transaction was voided if it was not # a freebie emailer.void_payment( link, campaign, reason=reason, total_budget_dollars=campaign.total_budget_dollars)
def auth_campaign(link, campaign, user, pay_id=None, freebie=False): """ Authorizes (but doesn't charge) a budget with authorize.net. Args: - link: promoted link - campaign: campaign to be authorized - user: Account obj of the user doing the auth (usually the currently logged in user) - pay_id: customer payment profile id to use for this transaction. (One user can have more than one payment profile if, for instance, they have more than one credit card on file.) Set pay_id to -1 for freebies. Returns: (True, "") if successful or (False, error_msg) if not. """ void_campaign(link, campaign, reason='changed_payment') if freebie: trans_id, reason = authorize.auth_freebie_transaction( campaign.total_budget_dollars, user, link, campaign._id) else: trans_id, reason = authorize.auth_transaction( campaign.total_budget_dollars, user, pay_id, link, campaign._id) if trans_id and not reason: text = ('updated payment and/or budget for campaign %s: ' 'SUCCESS (trans_id: %d, amt: %0.2f)' % (campaign._id, trans_id, campaign.total_budget_dollars)) PromotionLog.add(link, text) if trans_id < 0: PromotionLog.add(link, 'FREEBIE (campaign: %s)' % campaign._id) if trans_id: if is_finished(link): # When a finished promo gets a new paid campaign it doesn't # need to go through approval again and is marked accepted new_status = PROMOTE_STATUS.accepted else: new_status = max(PROMOTE_STATUS.unseen, link.promote_status) else: new_status = max(PROMOTE_STATUS.unpaid, link.promote_status) update_promote_status(link, new_status) if user and (user._id == link.author_id) and trans_id > 0: emailer.promo_total_budget(link, campaign.total_budget_dollars, campaign.start_date) else: text = ( "updated payment and/or budget for campaign %s: FAILED ('%s')" % (campaign._id, reason)) PromotionLog.add(link, text) trans_id = 0 campaign.trans_id = trans_id campaign._commit() return bool(trans_id), reason
def edit_campaign(link, campaign, dates, target, frequency_cap, priority, location, total_budget_pennies, cost_basis, bid_pennies, platform='desktop', mobile_os=None, ios_devices=None, ios_version_range=None, android_devices=None, android_version_range=None): changed = {} if dates[0] != campaign.start_date or dates[1] != campaign.end_date: original = '%s to %s' % (campaign.start_date, campaign.end_date) edited = '%s to %s' % (dates[0], dates[1]) changed['dates'] = (original, edited) campaign.start_date = dates[0] campaign.end_date = dates[1] if target != campaign.target: changed['target'] = (campaign.target, target) campaign.target = target if frequency_cap != campaign.frequency_cap: changed['frequency_cap'] = (campaign.frequency_cap, frequency_cap) campaign.frequency_cap = frequency_cap if priority != campaign.priority: changed['priority'] = (campaign.priority.name, priority.name) campaign.priority = priority if location != campaign.location: changed['location'] = (campaign.location, location) campaign.location = location if platform != campaign.platform: changed["platform"] = (campaign.platform, platform) campaign.platform = platform if mobile_os != campaign.mobile_os: changed["mobile_os"] = (campaign.mobile_os, mobile_os) campaign.mobile_os = mobile_os if ios_devices != campaign.ios_devices: changed['ios_devices'] = (campaign.ios_devices, ios_devices) campaign.ios_devices = ios_devices if android_devices != campaign.android_devices: changed['android_devices'] = (campaign.android_devices, android_devices) campaign.android_devices = android_devices if ios_version_range != campaign.ios_version_range: changed['ios_version_range'] = (campaign.ios_version_range, ios_version_range) campaign.ios_version_range = ios_version_range if android_version_range != campaign.android_version_range: changed['android_version_range'] = (campaign.android_version_range, android_version_range) campaign.android_version_range = android_version_range if total_budget_pennies != campaign.total_budget_pennies: void_campaign(link, campaign, reason='changed_budget') campaign.total_budget_pennies = total_budget_pennies if cost_basis != campaign.cost_basis: changed['cost_basis'] = (campaign.cost_basis, cost_basis) campaign.cost_basis = cost_basis if bid_pennies != campaign.bid_pennies: changed['bid_pennies'] = (campaign.bid_pennies, bid_pennies) campaign.bid_pennies = bid_pennies change_strs = map(lambda t: '%s: %s -> %s' % (t[0], t[1][0], t[1][1]), changed.iteritems()) change_text = ', '.join(change_strs) campaign._commit() # update the index PromotionWeights.reschedule(link, campaign) if not campaign.is_house: # make it a freebie, if applicable author = Account._byID(link.author_id, True) if getattr(author, "complimentary_promos", False): free_campaign(link, campaign, c.user) # record the changes if change_text: PromotionLog.add(link, 'edited %s: %s' % (campaign, change_text)) hooks.get_hook('promote.edit_campaign').call(link=link, campaign=campaign)