def _add_team_id(customer, default_team_id): team_ids = {} to_put = [] def _add_team_id_for_manager(manager_email): regio_manager = RegioManager.get(RegioManager.create_key(manager_email)) if regio_manager and regio_manager.team_id: team_ids[manager_email] = regio_manager.team_id to_put.append(customer) if customer.manager: _add_team_id_for_manager(customer.manager.email()) if customer.manager.email() in team_ids: customer.team_id = team_ids[customer.manager.email()] else: customer.team_id = default_team_id for order in Order.all().ancestor(customer): to_put.append(order) if order.manager: if order.manager.email() not in team_ids: _add_team_id_for_manager(order.manager.email()) if order.manager.email() in team_ids: order.team_id = team_ids[order.manager.email()] else: order.team_id = default_team_id else: order.team_id = default_team_id for charge in Charge.all().ancestor(customer): to_put.append(charge) if charge.manager: if charge.manager.email() not in team_ids: _add_team_id_for_manager(charge.manager.email()) if charge.manager.email() in team_ids: charge.team_id = team_ids[charge.manager.email()] else: charge.team_id = default_team_id else: charge.team_id = default_team_id else: customer.team_id = default_team_id for order in Order.all().ancestor(customer): to_put.append(order) order.team_id = default_team_id for charge in Charge.all().ancestor(customer): to_put.append(charge) charge.team_id = default_team_id if to_put: db.put(to_put)
def _change_orders_manager(manager_email, replacement_manager_email): logging.info('Setting regional manager on orders from %s to %s', manager_email, replacement_manager_email) to_put = [] replacement_user = users.User(replacement_manager_email) orders = Order.all().filter('manager', users.User(manager_email)).fetch(None) for order in orders: order.manager = replacement_user to_put.append(order) put_in_chunks(to_put)
def _all_subscription_orders(): return Order.all(keys_only=True) \ .filter('is_subscription_order =', True) \ .filter('next_charge_date =', NEVER_CHARGE_DATE)
def _qry(status): return Order.all(keys_only=True).filter("status", Order.STATUS_SIGNED).filter( 'is_subscription_order', True)
def _qry2(): return Order.all(keys_only=True).filter('next_charge_date', None)
def trans(): customer_id = order_key.parent().id() order, customer = db.get([order_key, Customer.create_key(customer_id)]) if not order.next_charge_date: logging.warning( 'Not creating recurrent charge for order %s (%s: %s) because no next charge date is set', order.order_number, customer_id, customer.name) return None elif order.next_charge_date > today: # Scenario: this job fails today, tomorrow this job runs again and fails again # -> 2 jobs for the same order would create 2 charges when the bug is fixed logging.warning( 'This order has already been charged this month, skipping... %s (%s: %s)', order.order_number, customer_id, customer.name) return None elif customer.subscription_cancel_pending_date: logging.info('Disabling service from customer %s (%d)', customer.name, customer.id) try: cancel_order(customer, order.order_number) except OrderAlreadyCanceledException as exception: logging.info('Order %s already canceled, continuing...', exception.order.order_number) set_service_disabled(customer, Customer.DISABLED_OTHER) cleanup_expired_subscription(customer) return None logging.info("Creating recurrent charge for order %s (%s: %s)", order.order_number, customer_id, customer.name) subscription_extension_orders = list( Order.all().ancestor(customer).filter( "next_charge_date <", today).filter("is_subscription_order =", False).filter( 'is_subscription_extension_order =', True).filter("status =", Order.STATUS_SIGNED)) # type: list[Order] subscription_extension_order_keys = [ o.key() for o in subscription_extension_orders ] order_item_qry = OrderItem.all().ancestor( customer if subscription_extension_order_keys else order) subscription_extension_order_item_keys = [] total_amount = 0 subscription_length = 0 current_date = datetime.datetime.utcnow() to_put = [] for order_item in order_item_qry: # type: OrderItem product = products[order_item.product_code] if order_item.order_number == order.order_number: if product.is_subscription: subscription_length = order_item.count if product.is_subscription or product.is_subscription_discount or product.is_subscription_extension: if product.charge_interval != 1: last_charge_date = datetime.datetime.utcfromtimestamp( order_item.last_charge_timestamp) new_charge_date = last_charge_date + relativedelta( months=product.charge_interval) if new_charge_date < current_date: logging.debug( 'new_charge_date %s < current_date %s, adding %s to total_amount', new_charge_date, current_date, order_item.price) total_amount += order_item.price order_item.last_charge_timestamp = now() to_put.append(order_item) else: total_amount += order_item.price elif order_item.parent().key( ) in subscription_extension_order_keys: if product.is_subscription_extension: total_amount += order_item.price subscription_extension_order_item_keys.append( order_item.key()) if total_amount == 0: order.next_charge_date = Order.default_next_charge_date() order.put() logging.info( "Skipping, cannot calculate recurrent charge of 0 euros for order %s (%s: %s)", order.order_number, customer_id, customer.name) return None if subscription_length == 0: raise Exception('subscription_length is 0') if not (customer.stripe_id and customer.stripe_credit_card_id) and subscription_length != 1: logging.debug( 'Tried to bill customer, but no credit card info was found') audit_log( customer.id, 'Tried to bill customer, but no credit card info was found') # Log the customer as expired. If this has not been done before. expired_subscription_key = ExpiredSubscription.create_key( customer_id) if not ExpiredSubscription.get(expired_subscription_key): to_put.append( ExpiredSubscription( key=expired_subscription_key, expiration_timestamp=order.next_charge_date)) # Create a task for the support manager assignee = customer.manager and customer.manager.email() if customer.team_id is not None: team = RegioManagerTeam.get_by_id(customer.team_id) if team.support_manager: assignee = team.support_manager if assignee: if customer.prospect_id: prospect = Prospect.get( Prospect.create_key(customer.prospect_id)) else: # We can only create tasks for prospects. So we must create a prospect if there was none. prospect = create_prospect_from_customer(customer) customer.prospect_id = prospect.id to_put.append(customer) to_put.append(prospect) to_put.append( create_task( created_by=None, prospect_or_key=prospect, assignee=assignee, execution_time=today + 11 * 3600, task_type=ShopTask.TYPE_SUPPORT_NEEDED, app_id=prospect.app_id, status=ShopTask.STATUS_NEW, comment= u"Customer needs to be contacted for subscription renewal", notify_by_email=True)) put_and_invalidate_cache(*to_put) return None else: cleanup_expired_subscription(customer) @db.non_transactional # prevent contention on entity group RegioManagerTeam def get_currency_code(): return customer.team.legal_entity.currency_code charge = Charge(parent=order_key) charge.date = now() charge.type = Charge.TYPE_RECURRING_SUBSCRIPTION charge.subscription_extension_length = 1 charge.subscription_extension_order_item_keys = subscription_extension_order_item_keys charge.currency_code = get_currency_code() charge.team_id = customer.team_id charge.amount = total_amount charge.vat_pct = order.vat_pct charge.vat = int(total_amount * order.vat_pct / 100) charge.total_amount = charge.amount + charge.vat to_put.append(charge) next_charge_datetime = datetime.datetime.utcfromtimestamp( order.next_charge_date) + relativedelta(months=1) next_charge_date_int = int( (next_charge_datetime - datetime.datetime.utcfromtimestamp(0)).total_seconds()) order.next_charge_date = next_charge_date_int to_put.append(order) for extension_order in subscription_extension_orders: extension_order.next_charge_date = next_charge_date_int to_put.append(extension_order) put_and_invalidate_cache(*to_put) return charge
def _qry(today): # next_charge_date is unset for free subscriptions return Order.all(keys_only=True) \ .filter("is_subscription_order =", True) \ .filter("next_charge_date <", today) \ .filter("status =", Order.STATUS_SIGNED)