def get_price_today(self, formatted=True): """ Return calculated price for a subscription, assuming TODAY_LOCAL is the startdate """ from decimal import Decimal, ROUND_HALF_UP from general_helpers import get_last_day_month db = current.db TODAY_LOCAL = current.TODAY_LOCAL CURRSYM = current.globalenv['CURRSYM'] price = self.get_price_on_date(TODAY_LOCAL, False) period_start = TODAY_LOCAL period_end = get_last_day_month(period_start) delta = period_end - period_start days = delta.days + 1 total_days = period_end.day price = Decimal(float(days) / float(total_days) * float(price)) price = price.quantize(Decimal('.01'), rounding=ROUND_HALF_UP) if formatted: return SPAN(CURRSYM, ' ', format(price, '.2f')) else: return price
def get_cancel_from_date(self, cancel_request_date=None): """ Get date from which this subscription can be cancelled (incl. cancellation period) :param cancel_request_date: Date from which to start calculating the date the subscription can be stopped, including the cancellation period :return: datetime.date """ from ..general_helpers import add_months_to_date, get_last_day_month TODAY_LOCAL = current.TODAY_LOCAL if not cancel_request_date: cancel_request_date = TODAY_LOCAL cancel_period = self.ssu.CancellationPeriod or 0 period_unit = self.ssu.CancellationPeriodUnit # This also takes care of the "months" period unit can_cancel_from_date = add_months_to_date(cancel_request_date, cancel_period) # Go to the last day of the month for the "calendar month" period unit if period_unit == "calendar_month": can_cancel_from_date = get_last_day_month(can_cancel_from_date) # Check if the returned date isn't before the minimum end date if can_cancel_from_date < self.min_enddate: can_cancel_from_date = self.min_enddate return can_cancel_from_date
def get_teachers_list_classes_in_month(self, year, month): """ :param year: int :param month: int :return: dict(teacher_id=[classes]) """ from openstudio.os_class_schedule import ClassSchedule from general_helpers import get_last_day_month ids = self.get_teacher_ids() start_date = datetime.date(year, month, 1) last_day = get_last_day_month(start_date) data = {} for teID in ids: teID = int(teID) data[teID] = {} data[teID]['classes'] = {} data[teID]['classes_count'] = 0 for each_day in range(1, last_day.day + 1): # list days day = datetime.date(year, month, each_day) weekday = day.isoweekday() class_schedule = ClassSchedule(date=day, filter_id_teacher=int(teID)) rows = class_schedule.get_day_rows() data[teID]['classes'][day] = rows data[teID]['classes_count'] += len(rows) return data
def get_price_today_display(self, formatted=False): """ Use this function to display subscription price to customers """ from decimal import Decimal, ROUND_HALF_UP from .tools import OsTools from general_helpers import get_last_day_month db = current.db os_tools = OsTools() CURRSYM = current.globalenv['CURRSYM'] TODAY_LOCAL = current.TODAY_LOCAL price_today = self.get_price_today(formatted=False) subscription_first_invoice_two_terms = os_tools.get_sys_property( 'subscription_first_invoice_two_terms') subscription_first_invoice_two_terms_from_day = \ int(os_tools.get_sys_property('subscription_first_invoice_two_terms_from_day') or 1) if subscription_first_invoice_two_terms == "on" \ and TODAY_LOCAL.day >= subscription_first_invoice_two_terms_from_day: first_next_month = get_last_day_month(TODAY_LOCAL) + datetime.timedelta(days=1) price_today += self.get_price_on_date(first_next_month, formatted = False) price_display = Decimal(price_today).quantize(Decimal('.01'), rounding=ROUND_HALF_UP) if formatted: return SPAN(CURRSYM, ' ', str(price_display)) else: return price_display
def index_process_request_vars(var=None): """ This function takes the request.vars as a argument and """ from general_helpers import get_last_day_month from general_helpers import datestr_to_python today = TODAY_LOCAL if 'date_from' in request.vars: date_from = datestr_to_python(DATE_FORMAT, request.vars['date_from']) elif not session.reports_tax_summary_index_date_from is None: date_from = session.reports_tax_summary_index_date_from else: date_from = datetime.date( today.year, today.month, 1 ) session.reports_tax_summary_index_date_from = date_from if 'date_until' in request.vars: date_until = datestr_to_python(DATE_FORMAT, request.vars['date_until']) elif not session.reports_tax_summary_index_date_until is None: date_until = session.reports_tax_summary_index_date_until else: date_until = get_last_day_month(today) session.reports_tax_summary_index_date_until = date_until
def add_credits_month(self, year, month): """ Add credits for selected month """ from .os_customers_subscriptions_credits import CustomersSubscriptionsCredits first_day = datetime.date(year, month, 1) last_day = get_last_day_month(first_day) if self.cs.Startdate <= first_day: p_start = first_day else: p_start = self.cs.Startdate if self.cs.Enddate is None or self.cs.Enddate >= last_day: p_end = last_day else: p_end = self.cs.Enddate csch = CustomersSubscriptionsCredits() csch.add_subscription_credits_month( self.csID, self.cs.auth_customer_id, year, month, p_start, p_end, self.ssu.Classes, self.ssu.SubscriptionUnit, batch_add=False, book_classes=False)
def add_credits_get_subscription_rows_month(self, year, month): """ return subscription rows for month """ db = current.db first_day = datetime.date(year, month, 1) last_day = get_last_day_month(first_day) fields = [ db.customers_subscriptions.id, db.customers_subscriptions.Startdate, db.customers_subscriptions.Enddate, db.customers_subscriptions.auth_customer_id, db.customers_subscriptions_credits.id, db.customers_subscriptions_paused.id, db.school_subscriptions.Name, db.school_subscriptions.Classes, db.school_subscriptions.SubscriptionUnit, db.school_subscriptions.Unlimited, ] query = """ SELECT cs.id, cs.Startdate, cs.Enddate, cs.auth_customer_id, csc.id, csp.id, ssu.Name, ssu.Classes, ssu.subscriptionunit, ssu.unlimited FROM customers_subscriptions cs LEFT JOIN ( SELECT id, SubscriptionYear, SubscriptionMonth, customers_subscriptions_id FROM customers_subscriptions_credits WHERE MutationType = 'add' AND SubscriptionYear = '{year}' AND SubscriptionMonth = '{month}' ) csc ON csc.customers_subscriptions_id = cs.id LEFT JOIN ( SELECT id, customers_subscriptions_id FROM customers_subscriptions_paused WHERE startdate <= '{last_day}' AND ENDDATE >= '{first_day}' ) csp ON csp.customers_subscriptions_id = cs.id LEFT JOIN school_subscriptions ssu ON cs.school_subscriptions_id = ssu.id WHERE cs.Startdate <= '{last_day}' AND (cs.Enddate >= '{first_day}' OR cs.Enddate IS NULL) """.format(year=year, month=month, first_day=first_day, last_day=last_day) rows = db.executesql(query, fields=fields) return rows
def subscription_buy_now(): """ Get a subscription """ ssuID = request.vars['ssuID'] # init mollie mollie = Client() mollie_api_key = get_sys_property('mollie_website_profile') mollie.set_api_key(mollie_api_key) create_mollie_customer(auth.user.id, mollie) # add subscription to customer startdate = TODAY_LOCAL shop_subscriptions_start = get_sys_property('shop_subscriptions_start') if not shop_subscriptions_start == None: if shop_subscriptions_start == 'next_month': startdate = get_last_day_month(TODAY_LOCAL) + datetime.timedelta( days=1) csID = db.customers_subscriptions.insert( auth_customer_id=auth.user.id, school_subscriptions_id=ssuID, Startdate=startdate, payment_methods_id= 100, # important, 100 is the payment_methods_id for Mollie ) # Add credits for the first month cs = CustomerSubscription(csID) cs.add_credits_month(startdate.year, startdate.month) # clear cache to make sure it shows in the back end cache_clear_customers_subscriptions(auth.user.id) # Create invoice cs = CustomerSubscription(csID) iID = cs.create_invoice_for_month(startdate.year, startdate.month) # Pay invoice ... SHOW ME THE MONEY!! :) redirect(URL('invoice_pay', vars={'iID': iID}))
def index_show_current_month(): """ Reset date from & until to this month :return: Redirect back to index """ from general_helpers import get_last_day_month today = TODAY_LOCAL date_from = datetime.date( today.year, today.month, 1 ) session.reports_tax_summary_index_date_from = date_from date_until = get_last_day_month(today) session.reports_tax_summary_index_date_until = date_until redirect(URL('index'))
def customers_subscriptions_create_invoices_for_month( self, year, month, description, invoice_date='today'): """ Actually create invoices for subscriptions for a given month """ from .os_customer_subscription import CustomerSubscription from general_helpers import get_last_day_month from .os_invoice import Invoice T = current.T db = current.db DATE_FORMAT = current.DATE_FORMAT year = int(year) month = int(month) firstdaythismonth = datetime.date(year, month, 1) lastdaythismonth = get_last_day_month(firstdaythismonth) invoices_count = 0 # get all active subscriptions in month query = (db.customers_subscriptions.Startdate <= lastdaythismonth) & \ ((db.customers_subscriptions.Enddate >= firstdaythismonth) | (db.customers_subscriptions.Enddate == None)) rows = db(query).select(db.customers_subscriptions.ALL) for row in rows: cs = CustomerSubscription(row.id) cs.create_invoice_for_month(year, month, description, invoice_date) invoices_count += 1 ## # For scheduled tasks db connection has to be committed manually ## db.commit() return T("Invoices in month") + ': ' + str(invoices_count)
def item_add_from_order_item(self, item): """ :param item: gluon.dal.row object of db.invoices_items :return: """ from .tools import OsTools from .os_school_subscription import SchoolSubscription from general_helpers import get_last_day_month db = current.db os_tools = OsTools() TODAY_LOCAL = current.TODAY_LOCAL if not item.customers_orders_items_shop_products_variants.id is None: # We have a product, use item_add_product_variant to create links and # update stock # print('######## item: ###########') # print(item) self.item_add_product_variant( pvID=item.customers_orders_items_shop_products_variants. shop_products_variants_id, quantity=item.customers_orders_items.Quantity) else: # We something else, just add. # print("receipt add item from oi") # print(item) sorting = self.get_item_next_sort_nr() riID = db.receipts_items.insert( receipts_id=self.receipts_id, Sorting=sorting, Custom=item.customers_orders_items.Custom, ProductName=item.customers_orders_items.ProductName, Description=item.customers_orders_items.Description, Quantity=item.customers_orders_items.Quantity, Price=item.customers_orders_items.Price, tax_rates_id=item.customers_orders_items.tax_rates_id, accounting_glaccounts_id=item.customers_orders_items. accounting_glaccounts_id, accounting_costcenters_id=item.customers_orders_items. accounting_costcenters_id) subscription_first_invoice_two_terms = os_tools.get_sys_property( 'subscription_first_invoice_two_terms') subscription_first_invoice_two_terms_from_day = \ int(os_tools.get_sys_property('subscription_first_invoice_two_terms_from_day') or 1) if subscription_first_invoice_two_terms == "on" \ and item.customers_orders_items.school_subscriptions_id \ and TODAY_LOCAL.day >= subscription_first_invoice_two_terms_from_day: # Add second item, with full price ssu = SchoolSubscription( item.customers_orders_items.school_subscriptions_id) first_next_month = get_last_day_month( TODAY_LOCAL) + datetime.timedelta(days=1) price = ssu.get_price_on_date(first_next_month, formatted=False) riID = db.receipts_items.insert( receipts_id=self.receipts_id, Sorting=sorting, Custom=item.customers_orders_items.Custom, ProductName=item.customers_orders_items.ProductName, Description=item.customers_orders_items.Description, Quantity=item.customers_orders_items.Quantity, Price=price, tax_rates_id=item.customers_orders_items.tax_rates_id, accounting_glaccounts_id=item.customers_orders_items. accounting_glaccounts_id, accounting_costcenters_id=item.customers_orders_items. accounting_costcenters_id) self.set_amounts()
def item_add_subscription(self, csID, SubscriptionYear, SubscriptionMonth, description=''): """ :param SubscriptionYear: Year of subscription :param SubscriptionMonth: Month of subscription :return: db.invoices_items.id """ T = current.T from general_helpers import get_last_day_month from .os_customer import Customer from .os_customer_subscription import CustomerSubscription from .os_school_subscription import SchoolSubscription db = current.db DATE_FORMAT = current.DATE_FORMAT next_sort_nr = self.get_item_next_sort_nr() date = datetime.date(int(SubscriptionYear), int(SubscriptionMonth), 1) cs = CustomerSubscription(csID) ssuID = cs.ssuID ssu = SchoolSubscription(ssuID) row = ssu.get_tax_rates_on_date(date) if row: tax_rates_id = row.school_subscriptions_price.tax_rates_id else: tax_rates_id = None period_start = date first_day_month = date last_day_month = get_last_day_month(date) period_end = last_day_month glaccount = ssu.get_glaccount_on_date(date) costcenter = ssu.get_costcenter_on_date(date) price = 0 # check for alt price csap = db.customers_subscriptions_alt_prices query = (csap.customers_subscriptions_id == csID) & \ (csap.SubscriptionYear == SubscriptionYear) & \ (csap.SubscriptionMonth == SubscriptionMonth) csap_rows = db(query).select(csap.ALL) if csap_rows: # alt. price overrides broken period csap_row = csap_rows.first() price = csap_row.Amount description = csap_row.Description else: price = ssu.get_price_on_date(date, False) broken_period = False pause = False # Check pause query = (db.customers_subscriptions_paused.customers_subscriptions_id == csID) & \ (db.customers_subscriptions_paused.Startdate <= last_day_month) & \ ((db.customers_subscriptions_paused.Enddate >= first_day_month) | (db.customers_subscriptions_paused.Enddate == None)) rows = db(query).select(db.customers_subscriptions_paused.ALL) if rows: pause = rows.first() # Calculate days to be paid if cs.startdate > first_day_month and cs.startdate <= last_day_month: # Start later in month broken_period = True period_start = cs.startdate if cs.enddate: if cs.enddate >= first_day_month and cs.enddate < last_day_month: # End somewhere in month broken_period = True period_end = cs.enddate Range = namedtuple('Range', ['start', 'end']) period_range = Range(start=period_start, end=period_end) period_days = (period_range.end - period_range.start).days + 1 if pause: # Set pause end date to period end if > period end pause_end = pause.Enddate if pause_end >= period_range.end: pause_end = period_range.end pause_range = Range(start=pause.Startdate, end=pause_end) latest_start = max(period_range.start, pause_range.start) earliest_end = min(pause_range.end, pause_range.end) delta = (earliest_end - latest_start).days + 1 overlap = max(0, delta) # Subtract pause overlap from period to be paid period_days = period_days - overlap month_days = (last_day_month - first_day_month).days + 1 price = round( ((float(period_days) / float(month_days)) * float(price)), 2) if not description: description = cs.name + ' ' + period_start.strftime( DATE_FORMAT) + ' - ' + period_end.strftime(DATE_FORMAT) if pause: description += '\n' description += "(" + T("Pause") + ": " description += pause.Startdate.strftime( DATE_FORMAT) + " - " description += pause.Enddate.strftime(DATE_FORMAT) + " | " description += T("Days paid this period: ") description += str(period_days) description += ")" iiID = db.invoices_items.insert(invoices_id=self.invoices_id, ProductName=current.T("Subscription") + ' ' + str(csID), Description=description, Quantity=1, Price=price, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, accounting_glaccounts_id=glaccount, accounting_costcenters_id=costcenter) ## # Check if a registration fee should be added # ; Add fee if a registration fee has ever been paid ## customer = Customer(cs.auth_customer_id) # query = ((db.customers_subscriptions.auth_customer_id == cs.auth_customer_id) & # (db.customers_subscriptions.RegistrationFeePaid == True)) fee_paid_in_past = customer.has_paid_a_subscription_registration_fee() ssu = db.school_subscriptions(ssuID) if not fee_paid_in_past and ssu.RegistrationFee: # Registration fee not already paid and RegistrationFee defined? regfee_to_be_paid = ssu.RegistrationFee or 0 if regfee_to_be_paid: db.invoices_items.insert( invoices_id=self.invoices_id, ProductName=current.T("Registration fee"), Description=current.T('One time registration fee'), Quantity=1, Price=regfee_to_be_paid, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, ) # Mark registration fee as paid for subscription db.customers_subscriptions[cs.csID] = dict( RegistrationFeePaid=True) ## # Always call these ## # Link invoice item to subscription self.link_item_to_customer_subscription(csID, iiID) # This calls self.on_update() self.set_amounts() return iiID
def create_invoice_for_month(self, SubscriptionYear, SubscriptionMonth): """ :param SubscriptionYear: Year of subscription :param SubscriptionMonth: Month of subscription """ from os_invoice import Invoice db = current.db TODAY_LOCAL = current.TODAY_LOCAL DATE_FORMAT = current.DATE_FORMAT # create invoice linked to subscription for first subscription term to know the right amount. SubscriptionYear = TODAY_LOCAL.year SubscriptionMonth = TODAY_LOCAL.month firstdaythismonth = datetime.date(SubscriptionYear, SubscriptionMonth, 1) lastdaythismonth = get_last_day_month(firstdaythismonth) left = [ db.invoices_customers_subscriptions.on( db.invoices_customers_subscriptions.invoices_id == db.invoices.id) ] # Check if an invoice already exists, if so, return invoice id query = (db.invoices_customers_subscriptions.customers_subscriptions_id == self.csID) & \ (db.invoices.SubscriptionYear == SubscriptionYear) & \ (db.invoices.SubscriptionMonth == SubscriptionMonth) rows = db(query).select(db.invoices.ALL, left=left) if len(rows): return rows.first().id # Check if the subscription is paused query = (db.customers_subscriptions_paused.customers_subscriptions_id == self.csID) & \ (db.customers_subscriptions_paused.Startdate <= lastdaythismonth) & \ ((db.customers_subscriptions_paused.Enddate >= firstdaythismonth) | (db.customers_subscriptions_paused.Enddate == None)) if db(query).count(): return # Check if an alt. price with amount 0 has been defined csap = db.customers_subscriptions_alt_prices query = (csap.customers_subscriptions_id == self.csID) & \ (csap.SubscriptionYear == SubscriptionYear) & \ (csap.SubscriptionMonth == SubscriptionMonth) csap_rows = db(query).select(csap.ALL) if csap_rows: csap_row = csap_rows.first() if csap_row.Amount == 0: return # Ok we've survived all checks, continue with invoice creation igpt = db.invoices_groups_product_types(ProductType='subscription') igID = igpt.invoices_groups_id if TODAY_LOCAL > firstdaythismonth: period_begin = TODAY_LOCAL else: period_begin = firstdaythismonth period_end = lastdaythismonth if self.enddate: if self.startdate >= firstdaythismonth and \ self.enddate < lastdaythismonth: period_end = self.enddate item_description = period_begin.strftime(DATE_FORMAT) + ' - ' + \ period_end.strftime(DATE_FORMAT) iID = db.invoices.insert(invoices_groups_id=igID, payment_methods_id=self.payment_methods_id, customers_subscriptions_id=self.csID, SubscriptionYear=SubscriptionYear, SubscriptionMonth=SubscriptionMonth, Description='', Status='sent') # create object to set Invoice# and due date invoice = Invoice(iID) invoice.link_to_customer(self.auth_customer_id) invoice.link_to_customer_subscription(self.csID) invoice.item_add_subscription(SubscriptionYear, SubscriptionMonth) return iID
def add_subscription_credits_month(self, csID, cuID, year, month, p_start, p_end, classes, subscription_unit, batch_add=True, book_classes=True): """ Insert subscription credits and clear cache for customer subscription :param csID: db.customers_subscriptions.id :param cuID: db.auth_user.id :param year: int :param month: int :param p_start: datetime.date (Period start) :param p_end: datetime.date (Period end) :param classes: int :param subscription_unit: string either 'week' or 'month' :return: None """ from .os_attendance_helper import AttendanceHelper from .os_customer_subscription import CustomerSubscription T = current.T db = current.db now = current.NOW_LOCAL cache_clear_customers_subscriptions = current.globalenv[ 'cache_clear_customers_subscriptions'] TODAY_LOCAL = current.TODAY_LOCAL first_day = datetime.date(year, month, 1) last_day = get_last_day_month(first_day) t_days = (last_day - first_day) + datetime.timedelta( days=1) # Total days (Add 1, when subsctraced it's one day less) p_days = (p_end - p_start) + datetime.timedelta(days=1) # Period days percent = float(p_days.days) / float(t_days.days) if subscription_unit == 'month': credits = round(classes * percent, 1) else: weeks_in_month = round(t_days.days / float(7), 1) credits = round((weeks_in_month * (classes or 0)) * percent, 1) mutation_datetime = now # Check if credits have already been added for this subscription. query = (db.customers_subscriptions_credits.MutationType == "add") & \ (db.customers_subscriptions_credits.customers_subscriptions_id == csID) if not db(query).count(): # No credits found yet, so add on the start of the subscription mutation_datetime = p_start db.customers_subscriptions_credits.insert( customers_subscriptions_id=csID, MutationDateTime=mutation_datetime, MutationType='add', MutationAmount=credits, Description=T('Credits') + ' ' + first_day.strftime('%B %Y'), SubscriptionYear=year, SubscriptionMonth=month) if batch_add: try: self.add_credits_balance[cuID] += credits except KeyError: self.add_credits_balance[cuID] = credits else: cs = CustomerSubscription(csID) self.add_credits_balance[cuID] = cs.get_credits_balance() if book_classes: # Get list of classes for customer in a given month, based on reservations classes_this_month = self.add_credits_reservations.get(cuID, False) ah = AttendanceHelper() if classes_this_month: # Book classess while len(self.add_credits_reservations.get( cuID)) > 0 and self.add_credits_balance[cuID] > 0: # Sign in to a class ## # remove this reservation from the list, as we have just booked it, so it won't be booked again using # another subscription ## reservation = self.add_credits_reservations[cuID].pop( 0 ) # always get the first in the list, we pop all classes already booked ah.attendance_sign_in_subscription(cuID, reservation['clsID'], csID, reservation['date']) # Subtract one credit from current balance in this object (self.add_credits_balance) self.add_credits_balance[cuID] -= 1 # Clear cache cache_clear_customers_subscriptions(cuID)
def add_credits(self, year, month): """ Add subscription credits for month """ from .os_customers import Customers T = current.T db = current.db first_day = datetime.date(year, month, 1) last_day = get_last_day_month(first_day) # Get list of bookable classes for each customer, based on recurring reservations self.add_credits_reservations = self._get_customers_list_classes_recurring_reservations( year, month) # Get list of total credits balance for each customer customers = Customers() self.add_credits_balance = customers.get_credits_balance( first_day, include_reconciliation_classes=True) customers_credits_added = 0 rows = self.add_credits_get_subscription_rows_month(year, month) for row in rows: # Don't do anything if this subscription already got credits for this month is paused # or has no classes or subscription unit defined if row.customers_subscriptions_credits.id: continue if row.customers_subscriptions_paused.id: continue if row.school_subscriptions.Classes == 0 or row.school_subscriptions.Classes is None: continue if row.school_subscriptions.SubscriptionUnit is None: continue # calculate number of credits # only add partial credits if startdate != first day, add full credits if startdate < first day if row.customers_subscriptions.Startdate <= first_day: p_start = first_day else: p_start = row.customers_subscriptions.Startdate if row.customers_subscriptions.Enddate is None or row.customers_subscriptions.Enddate >= last_day: p_end = last_day else: p_end = row.customers_subscriptions.Enddate self.add_subscription_credits_month( row.customers_subscriptions.id, row.customers_subscriptions.auth_customer_id, year, month, p_start, p_end, row.school_subscriptions.Classes, row.school_subscriptions.SubscriptionUnit, ) # Increase counter customers_credits_added += 1 return customers_credits_added or 0
def _get_customers_list_classes_recurring_reservations(self, year, month): """ Get list of classes a customer has a reservation for in a selected month """ from .os_attendance_helper import AttendanceHelper from .os_class_schedule import ClassSchedule from .os_classes_reservations import ClassesReservations db = current.db ah = AttendanceHelper() crh = ClassesReservations() first_day = datetime.date(year, month, 1) last_day = get_last_day_month(first_day) data = {} date = first_day while date <= last_day: # get list of classes on date #print date cs = ClassSchedule(date) #print 'getting classes' classes = cs.get_day_list() reservations = crh.get_recurring_reservations_on_date(date) for cls in classes: if cls['Cancelled'] or cls['Holiday']: # Class is cancelled or in a holiday, nothing to do continue # Get list of bookings with status "attending" or "booked" #print 'getting attendance for class' attending = [] rows = ah.get_attendance_rows(cls['ClassesID'], date) for row in rows: # print row if row.classes_attendance.BookingStatus == 'booked' or \ row.classes_attendance.BookingStatus == 'attending': attending.append(row.auth_user.id) # if classes_id found on both lists, add class to reservations list for that customer for res in reservations: if res.classes_id == cls['ClassesID']: # add customer to list in case not already attending if not res.auth_customer_id in attending: #print res.auth_customer_id value = {'clsID': cls['ClassesID'], 'date': date} # print value # print '###############' try: data[res.auth_customer_id].append(value) except KeyError: data[res.auth_customer_id] = [value] date += datetime.timedelta(days=1) return data
def item_add_subscription(self, SubscriptionYear, SubscriptionMonth, description=''): """ :param SubscriptionYear: Year of subscription :param SubscriptionMonth: Month of subscription :return: db.invoices_items.id """ from general_helpers import get_last_day_month from os_customer_subscription import CustomerSubscription from os_school_subscription import SchoolSubscription db = current.db DATE_FORMAT = current.DATE_FORMAT next_sort_nr = self.get_item_next_sort_nr() date = datetime.date(int(SubscriptionYear), int(SubscriptionMonth), 1) ics = db.invoices_customers_subscriptions(invoices_id=self.invoices_id) csID = ics.customers_subscriptions_id cs = CustomerSubscription(csID) ssuID = cs.ssuID ssu = SchoolSubscription(ssuID) row = ssu.get_tax_rates_on_date(date) if row: tax_rates_id = row.school_subscriptions_price.tax_rates_id else: tax_rates_id = None period_start = date period_end = get_last_day_month(date) glaccount = ssu.get_glaccount_on_date(date) costcenter = ssu.get_costcenter_on_date(date) price = 0 # check for alt price csap = db.customers_subscriptions_alt_prices query = (csap.customers_subscriptions_id == csID) & \ (csap.SubscriptionYear == SubscriptionYear) & \ (csap.SubscriptionMonth == SubscriptionMonth) csap_rows = db(query).select(csap.ALL) if csap_rows: csap_row = csap_rows.first() price = csap_row.Amount description = csap_row.Description else: price = ssu.get_price_on_date(date, False) broken_period = False if cs.startdate > date and cs.startdate <= period_end: # Start later in month broken_period = True period_start = cs.startdate delta = period_end - cs.startdate cs_days = delta.days + 1 total_days = period_end.day if cs.enddate: if cs.enddate >= date and cs.enddate < period_end: # End somewhere in month broken_period = True delta = cs.enddate - date cs_days = delta.days + 1 total_days = period_end.day period_end = cs.enddate if broken_period: price = round( float(cs_days) / float(total_days) * float(price), 2) if not description: description = cs.name.decode( 'utf-8') + u' ' + period_start.strftime( DATE_FORMAT) + u' - ' + period_end.strftime( DATE_FORMAT) iiID = db.invoices_items.insert(invoices_id=self.invoices_id, ProductName=current.T("Subscription") + ' ' + unicode(csID), Description=description, Quantity=1, Price=price, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, accounting_glaccounts_id=glaccount, accounting_costcenters_id=costcenter) ## # Check if a registration fee should be added ## query = ( ((db.customers_subscriptions.auth_customer_id == cs.auth_customer_id) & (db.customers_subscriptions.id != cs.csID) & (db.customers_subscriptions.school_subscriptions_id == cs.ssuID)) | (db.customers_subscriptions.RegistrationFeePaid == True)) fee_paid_in_past = db(query).count() ssu = db.school_subscriptions(ssuID) if not fee_paid_in_past and ssu.RegistrationFee: # Registration fee not already paid and RegistrationFee defined? regfee_to_be_paid = ssu.RegistrationFee or 0 if regfee_to_be_paid: db.invoices_items.insert( invoices_id=self.invoices_id, ProductName=current.T("Registration fee"), Description=current.T('One time registration fee'), Quantity=1, Price=regfee_to_be_paid, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, ) # Mark registration fee as paid for subscription db.customers_subscriptions[cs.csID] = dict( RegistrationFeePaid=True) ## # Always call these ## # This calls self.on_update() self.set_amounts() return iiID
def create_invoice_for_month(self, SubscriptionYear, SubscriptionMonth, description=None, invoice_date='today'): """ :param SubscriptionYear: Year of subscription :param SubscriptionMonth: Month of subscription """ from .os_school_subscription import SchoolSubscription from .os_invoice import Invoice T = current.T db = current.db TODAY_LOCAL = current.TODAY_LOCAL DATE_FORMAT = current.DATE_FORMAT firstdaythismonth = datetime.date(SubscriptionYear, SubscriptionMonth, 1) lastdaythismonth = get_last_day_month(firstdaythismonth) left = [ db.invoices_items.on( db.invoices_items.invoices_id == db.invoices.id ), db.invoices_items_customers_subscriptions.on( db.invoices_items_customers_subscriptions.invoices_items_id == db.invoices_items.id ), ] # Check if an invoice already exists, if so, return invoice id query = (db.invoices_items_customers_subscriptions.customers_subscriptions_id == self.csID) & \ (db.invoices.SubscriptionYear == SubscriptionYear) & \ (db.invoices.SubscriptionMonth == SubscriptionMonth) rows = db(query).select(db.invoices.ALL, left=left) if len(rows): return rows.first().id # Check if the subscription is paused the full month query = (db.customers_subscriptions_paused.customers_subscriptions_id == self.csID) & \ (db.customers_subscriptions_paused.Startdate <= firstdaythismonth) & \ ((db.customers_subscriptions_paused.Enddate >= lastdaythismonth) | (db.customers_subscriptions_paused.Enddate == None)) if db(query).count(): # This subscription is paused the full month, nothing to do return # Check if the customer has been moved to deleted customer = db.auth_user(self.cs.auth_customer_id) if customer.trashed: # Customer has been trashed, don't do anything return # Check if an alt. price with amount 0 has been defined csap = db.customers_subscriptions_alt_prices query = (csap.customers_subscriptions_id == self.csID) & \ (csap.SubscriptionYear == SubscriptionYear) & \ (csap.SubscriptionMonth == SubscriptionMonth) csap_rows = db(query).select(csap.ALL) if csap_rows: csap_row = csap_rows.first() if csap_row.Amount == 0: return # Check if the regular price is 0 school_subscription = SchoolSubscription(self.ssuID) price = school_subscription.get_price_on_date( firstdaythismonth, formatted=False ) if price == 0: # No need to create an invoice return # Ok we've survived all checks, continue with invoice creation igpt = db.invoices_groups_product_types(ProductType='subscription') igID = igpt.invoices_groups_id if not description: description = T("Subscription") if invoice_date == 'first_of_month': date_created = datetime.date( int(SubscriptionYear), int(SubscriptionMonth), 1 ) else: date_created = TODAY_LOCAL iID = db.invoices.insert( invoices_groups_id=igID, payment_methods_id=self.payment_methods_id, customers_subscriptions_id=self.csID, SubscriptionYear=SubscriptionYear, SubscriptionMonth=SubscriptionMonth, Description=description, Status='sent', DateCreated=date_created ) # create object to set Invoice# and due date invoice = Invoice(iID) invoice.link_to_customer(self.auth_customer_id) iiID = invoice.item_add_subscription(self.csID, SubscriptionYear, SubscriptionMonth) return iID
def my_classes(): """ creates page that displays the classes tought montlhy :return: """ response.title = T("Employee Portal") response.subtitle = SPAN(T("My classes"), XML(' • ')) response.view = 'ep/only_content.html' if session.ep_my_classes_month is None or session.ep_my_classes_year is None: session.ep_my_classes_year = TODAY_LOCAL.year session.ep_my_classes_month = TODAY_LOCAL.month table = TABLE(_class='table table-hover') table.append( THEAD( TR( TH(), TH(T('Date')), TH(T('Time')), TH(T('Location')), TH(T('Class Type')), TH(), #sub requested #TH(), # actions ))) date = datetime.date(session.ep_my_classes_year, session.ep_my_classes_month, 1) last_day = get_last_day_month(date) for each_day in range(1, last_day.day + 1): # list days day = datetime.date(session.ep_my_classes_year, session.ep_my_classes_month, each_day) class_schedule = ClassSchedule(date=day, filter_id_teacher=auth.user.id) rows = class_schedule.get_day_rows() for i, row in enumerate(rows): repr_row = list(rows[i:i + 1].render())[0] result = class_schedule._get_day_row_status(row) status_marker = result['marker'] button = '' sub_requested = '' if day >= TODAY_LOCAL: open_class = db.classes_otc(classes_id=row.classes.id, ClassDate=day, Status='open') if not open_class: button = os_gui.get_button('noicon', URL('request_sub', vars={ 'clsID': row.classes.id, 'date': day, 'teachers_id': auth.user.id }), title='Find sub', _class='pull-right', btn_class='btn-success') else: sub_requested = os_gui.get_label('primary', T("Sub requested")) button = os_gui.get_button( 'noicon', URL('cancel_request_sub', vars={'cotcID': open_class.id}), title='Cancel', _class='pull-right', btn_class='btn-warning') tr = TR( TD(status_marker, _class='td_status_marker'), TD(day.strftime(DATE_FORMAT)), TD(repr_row.classes.Starttime, '- ', repr_row.classes.Endtime), TD(repr_row.classes.school_locations_id), TD(repr_row.classes.school_classtypes_id), TD(sub_requested), TD(button)) table.append(tr) form_subtitle = get_form_subtitle(session.ep_my_classes_month, session.ep_my_classes_year, request.function, _class='col-md-8') response.subtitle.append(form_subtitle['subtitle']) month_chooser = form_subtitle['month_chooser'] current_month = form_subtitle['current_month'] header_tools = month_chooser + current_month return dict(header_tools=header_tools, content=table)
def customers_memberships_renew_expired(self, year, month): """ Checks if a subscription exceeds the expiration of a membership. If so it creates a new membership and an invoice for it for the customer """ from general_helpers import get_last_day_month from datetime import timedelta from os_customer import Customer from os_invoice import Invoice from os_school_membership import SchoolMembership T = current.T db = current.db DATE_FORMAT = current.DATE_FORMAT year = int(year) month = int(month) firstdaythismonth = datetime.date(year, month, 1) lastdaythismonth = get_last_day_month(firstdaythismonth) firstdaynextmonth = lastdaythismonth + datetime.timedelta(days=1) query = (db.customers_memberships.Enddate >= firstdaythismonth) & \ (db.customers_memberships.Enddate <= lastdaythismonth) rows = db(query).select( db.customers_memberships.ALL ) renewed = 0 for row in rows: new_cm_start = row.Enddate + datetime.timedelta(days=1) # Check if a subscription will be active next month for customer # if so, add another membership customer = Customer(row.auth_customer_id) # Check if a new membership hasn't ben added already if customer.has_membership_on_date(new_cm_start): continue # Ok all good, continue if customer.has_subscription_on_date(firstdaynextmonth, from_cache=False): new_cm_start = row.Enddate + datetime.timedelta(days=1) school_membership = SchoolMembership(row.school_memberships_id) school_membership.sell_to_customer( row.auth_customer_id, new_cm_start, note=T("Renewal for membership %s" % row.id), invoice=True, payment_methods_id=row.payment_methods_id ) renewed += 1 # else: # # print 'no subscription' # print renewed ## # For scheduled tasks db connection has to be committed manually ## db.commit() return T("Memberships renewed") + ': ' + unicode(renewed)
def customers_subscriptions_create_invoices_for_month(self, year, month, description): """ Actually create invoices for subscriptions for a given month """ from general_helpers import get_last_day_month from os_invoice import Invoice T = current.T db = current.db DATE_FORMAT = current.DATE_FORMAT year = int(year) month = int(month) firstdaythismonth = datetime.date(year, month, 1) lastdaythismonth = get_last_day_month(firstdaythismonth) csap = db.customers_subscriptions_alt_prices fields = [ db.customers_subscriptions.id, db.customers_subscriptions.auth_customer_id, db.customers_subscriptions.school_subscriptions_id, db.customers_subscriptions.Startdate, db.customers_subscriptions.Enddate, db.customers_subscriptions.payment_methods_id, db.school_subscriptions.Name, db.school_subscriptions_price.Price, db.school_subscriptions_price.tax_rates_id, db.tax_rates.Percentage, db.customers_subscriptions_paused.id, db.invoices.id, csap.id, csap.Amount, csap.Description ] rows = db.executesql( """ SELECT cs.id, cs.auth_customer_id, cs.school_subscriptions_id, cs.Startdate, cs.Enddate, cs.payment_methods_id, ssu.Name, ssp.Price, ssp.tax_rates_id, tr.Percentage, csp.id, i.invoices_id, csap.id, csap.Amount, csap.Description FROM customers_subscriptions cs LEFT JOIN auth_user au ON au.id = cs.auth_customer_id LEFT JOIN school_subscriptions ssu ON cs.school_subscriptions_id = ssu.id LEFT JOIN (SELECT id, school_subscriptions_id, Startdate, Enddate, Price, tax_rates_id FROM school_subscriptions_price WHERE Startdate <= '{firstdaythismonth}' AND (Enddate >= '{firstdaythismonth}' OR Enddate IS NULL)) ssp ON ssp.school_subscriptions_id = ssu.id LEFT JOIN tax_rates tr ON ssp.tax_rates_id = tr.id LEFT JOIN (SELECT id, customers_subscriptions_id FROM customers_subscriptions_paused WHERE Startdate <= '{firstdaythismonth}' AND (Enddate >= '{firstdaythismonth}' OR Enddate IS NULL)) csp ON cs.id = csp.customers_subscriptions_id LEFT JOIN (SELECT ics.id, ics.invoices_id, ics.customers_subscriptions_id FROM invoices_customers_subscriptions ics LEFT JOIN invoices on ics.invoices_id = invoices.id WHERE invoices.SubscriptionYear = {year} AND invoices.SubscriptionMonth = {month}) i ON i.customers_subscriptions_id = cs.id LEFT JOIN (SELECT id, customers_subscriptions_id, Amount, Description FROM customers_subscriptions_alt_prices WHERE SubscriptionYear = {year} AND SubscriptionMonth = {month}) csap ON csap.customers_subscriptions_id = cs.id WHERE cs.Startdate <= '{lastdaythismonth}' AND (cs.Enddate >= '{firstdaythismonth}' OR cs.Enddate IS NULL) AND ssp.Price <> 0 AND ssp.Price IS NOT NULL AND au.trashed = 'F' """.format(firstdaythismonth=firstdaythismonth, lastdaythismonth =lastdaythismonth, year=year, month=month), fields=fields) igpt = db.invoices_groups_product_types(ProductType = 'subscription') igID = igpt.invoices_groups_id invoices_created = 0 # Alright, time to create some invoices for row in rows: if row.invoices.id: # an invoice already exists, do nothing continue if row.customers_subscriptions_paused.id: # the subscription is paused, don't create an invoice continue if row.customers_subscriptions_alt_prices.Amount == 0: # Don't create an invoice if there's an alt price for the subscription with amount 0. continue csID = row.customers_subscriptions.id cuID = row.customers_subscriptions.auth_customer_id pmID = row.customers_subscriptions.payment_methods_id subscr_name = row.school_subscriptions.Name if row.customers_subscriptions_alt_prices.Description: inv_description = row.customers_subscriptions_alt_prices.Description else: inv_description = description if row.customers_subscriptions.Startdate > firstdaythismonth: period_begin = row.customers_subscriptions.Startdate else: period_begin = firstdaythismonth period_end = lastdaythismonth if row.customers_subscriptions.Enddate: if row.customers_subscriptions.Enddate >= firstdaythismonth and \ row.customers_subscriptions.Enddate < lastdaythismonth: period_end = row.customers_subscriptions.Enddate item_description = period_begin.strftime(DATE_FORMAT) + ' - ' + \ period_end.strftime(DATE_FORMAT) iID = db.invoices.insert( invoices_groups_id = igID, payment_methods_id = pmID, SubscriptionYear = year, SubscriptionMonth = month, Description = inv_description, Status = 'sent' ) # create object to set Invoice# and due date invoice = Invoice(iID) invoice.link_to_customer(cuID) invoice.link_to_customer_subscription(csID) invoice.item_add_subscription(year, month) invoice.set_amounts() invoices_created += 1 ## # For scheduled tasks db connection has to be committed manually ## db.commit() return T("Invoices created") + ': ' + unicode(invoices_created)
def _get_workshops_shop(self): """ Format list of workshops in a suitable way for the shop """ def new_workshop_month(): _class = 'workshops-list-month' return DIV(H2(last_day_month.strftime('%B %Y'), _class='center'), _class=_class) from general_helpers import get_last_day_month request = current.request os_gui = current.globalenv['os_gui'] T = current.T TODAY_LOCAL = current.TODAY_LOCAL rows = self.get_workshops_rows() current_month = TODAY_LOCAL last_day_month = get_last_day_month(current_month) workshops_month = new_workshop_month() workshops_month_body = DIV(_class='box-body') workshops = DIV() for i, row in enumerate(rows): repr_row = list(rows[i:i + 1].render())[0] more_info = os_gui.get_button( 'noicon', URL('event', vars={'wsID': row.workshops.id}), title=T('More info...'), btn_class='btn-link', btn_size='', _class='workshops-list-workshop-more-info') # Check if we're going into a later month if row.workshops.Startdate > last_day_month: if len(workshops_month_body) >= 1: # check if we have more in the month than just the title (the 1 in len()) workshops_month.append( DIV(workshops_month_body, _class='box box-solid')) workshops.append(workshops_month) last_day_month = get_last_day_month(row.workshops.Startdate) workshops_month = new_workshop_month() workshops_month_body = DIV(_class='box-body') startdate = SPAN( row.workshops.Startdate.strftime('%d %B').lstrip("0").replace( " 0", " "), _class='label_date') enddate = '' if not row.workshops.Startdate == row.workshops.Enddate: enddate = SPAN(row.workshops.Enddate.strftime('%d %B').lstrip( "0").replace(" 0", " "), _class='label_date') workshop = DIV( DIV(DIV(DIV(repr_row.workshops.thumblarge, _class='workshops-list-workshop-image center'), _class='col-xs-12 col-sm-12 col-md-3'), DIV(A(H3(row.workshops.Name), _href=URL('shop', 'event', vars={'wsID': row.workshops.id})), H4(repr_row.workshops.Tagline), DIV(os_gui.get_fa_icon('fa-calendar-o'), ' ', startdate, ' ', repr_row.workshops.Starttime, ' - ', enddate, ' ', repr_row.workshops.Endtime, _class='workshops-list-workshop-date'), DIV(os_gui.get_fa_icon('fa-user-o'), ' ', repr_row.workshops.auth_teacher_id, _class='workshops-list-workshop-teacher'), DIV(os_gui.get_fa_icon('fa-map-marker'), ' ', repr_row.workshops.school_locations_id, _class='workshops-list-workshop-location'), BR(), more_info, _class= 'col-xs-12 col-sm-12 col-md-9 workshops-list-workshop-info' ), _class=''), _class= 'workshops-list-workshop col-md-8 col-md-offset-2 col-xs-12') workshops_month_body.append(workshop) # if we're at the last row, add the workshops to the page if i + 1 == len(rows): workshops_month.append( DIV(workshops_month_body, _class='box box-solid')) workshops.append(workshops_month) return workshops
def get_subscriptions_formatted(self, auth_customer_id=None, per_row=3, public_only=True, link_type='shop'): """ :param public: boolean, defines whether to show only public or all subscriptions :return: list of school_subscriptions formatted for shop """ from general_helpers import get_last_day_month from openstudio.os_school_subscription import SchoolSubscription from openstudio.os_customer import Customer T = current.T TODAY_LOCAL = current.TODAY_LOCAL os_gui = current.globalenv['os_gui'] get_sys_property = current.globalenv['get_sys_property'] customer_has_membership = False customer_subscriptions_ids = [] if auth_customer_id: startdate = TODAY_LOCAL shop_subscriptions_start = get_sys_property( 'shop_subscriptions_start') if not shop_subscriptions_start == None: if shop_subscriptions_start == 'next_month': startdate = get_last_day_month( TODAY_LOCAL) + datetime.timedelta(days=1) customer = Customer(auth_customer_id) customer_has_membership = customer.has_membership_on_date( startdate) customer_subscriptions_ids = customer.get_school_subscriptions_ids_on_date( startdate) if per_row == 3: card_class = 'col-md-4' elif per_row == 4: card_class = 'col-md-3' else: raise ValueError('Incompatible value: per_row has to be 3 or 4') rows = self.get_subscriptions(public_only=public_only) subscriptions = DIV() display_row = DIV(_class='row') row_item = 0 for i, row in enumerate(rows): repr_row = list(rows[i:i + 1].render())[0] ssu = SchoolSubscription(row.id) name = max_string_length(row.Name, 33) classes = '' classes_unit = '' classes_text = T("Classes") if row.Unlimited: classes = T('Unlimited') classes_unit = T("Classes") elif row.SubscriptionUnit == 'week': if row.Classes == 1: classes_text = T("Class") classes = SPAN(str(row.Classes) + ' ' + classes_text) classes_unit = T("Per week") elif row.SubscriptionUnit == 'month': if row.Classes == 1: classes_text = T("Class") classes = SPAN(str(row.Classes) + ' ' + classes_text) classes_unit = T("Per month") subscription = DIV(DIV( self._get_formatted_display_widget_header( name, ssu.get_price_on_date(TODAY_LOCAL), ), DIV(DIV(T("Minimum duration"), ': ', repr_row.MinDuration, _class='col-md-12 bold'), DIV(repr_row.Description, _class='col-md-12'), _class='box-body'), DIV( DIV(DIV(DIV(H5('Payment', _class="description-header"), SPAN(T("Monthly"), _class="description-text"), _class="description-block"), _class="col-sm-4 border-right"), DIV(DIV(H5(classes, _class="description-header"), SPAN(classes_unit, _class="description-text"), _class="description-block"), _class="col-sm-4 border-right"), DIV(DIV(H5( self._get_subscriptions_formatted_button_to_cart( row.id, row.school_memberships_id, customer_subscriptions_ids), _class="description-header"), SPAN(T(""), _class="description-text"), _class="description-block"), _class="col-sm-4"), _class="row"), _class="box-footer", ), _class="box box-widget widget-user"), _class=card_class) # subscription_content = TABLE(TR(TD(T('Classes')), # TD(classes)), # TR(TD(T('Monthly')), # TD(ssu.get_price_on_date(datetime.date.today()))), # TR(TD(T('Description')), # TD(row.Description or '')), # _class='table') # # panel_class = 'box-primary' # # footer_content = '' # if link_type == 'shop': # footer_content = self._get_subscriptions_formatted_button_to_cart( # row.id, # row.MembershipRequired, # customer_has_membership, # customer_subscriptions_ids # ) # # subscription = DIV(os_gui.get_box_table(name, # subscription_content, # panel_class, # show_footer=True, # footer_content=footer_content), # _class=card_class) display_row.append(subscription) row_item += 1 if row_item == per_row or i == (len(rows) - 1): subscriptions.append(display_row) display_row = DIV(_class='row') row_item = 0 return subscriptions