def shoppingcart_remove_past_classes(self): """ Check if a class is already past, if so, remove it from the shopping cart. """ from os_class import Class import pytz T = current.T db = current.db now = current.NOW_LOCAL TIMEZONE = current.TIMEZONE message = False query = (db.customers_shoppingcart.auth_customer_id == self.cuID) & \ (db.customers_shoppingcart.classes_id != None) rows = db(query).select(db.customers_shoppingcart.id, db.customers_shoppingcart.classes_id, db.customers_shoppingcart.ClassDate) for row in rows: cls = Class(row.classes_id, row.ClassDate) if cls.is_past(): del_query = (db.customers_shoppingcart.id == row.id) db(query).delete() message = T( 'One past class was removed from your shopping cart') return message
def item_add_teacher_class_credit_travel_allowance(self, clsID, date, amount, tax_rates_id): """ :param clsID: db.classes.id :param date: datetime.date class date :return: """ from os_class import Class from os_teacher import Teacher DATE_FORMAT = current.DATE_FORMAT TIME_FORMAT = current.TIME_FORMAT db = current.db T = current.T cls = Class(clsID, date) # add item to invoice next_sort_nr = self.get_item_next_sort_nr() iiID = db.invoices_items.insert( invoices_id=self.invoices_id, ProductName=T('Travel allowance'), Description=cls.get_name(), Quantity=1, Price=amount * -1, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, ) self.set_amounts() self.on_update() return iiID
def verify(self): """ Verify class attendance :return: """ from os_class import Class auth = current.auth NOW_LOCAL = current.NOW_LOCAL cls = Class(self.row.classes_id, self.row.ClassDate) teachers = cls.get_teachers() self.row.auth_teacher_id = teachers['teacher']['id'] try: self.row.auth_teacher_id2 = teachers['teacher2']['id'] except (KeyError, TypeError): pass self.row.VerifiedBy = auth.user.id self.row.Status = 'verified' self.row.VerifiedOn = NOW_LOCAL result = self.row.update_record() return result
def item_add_teacher_class_credit_payment(self, clsID, date, payment_type='fixed_rate'): """ :param clsID: db.classes.id :param date: datetime.date class date :return: """ from os_class import Class from os_teacher import Teacher DATE_FORMAT = current.DATE_FORMAT TIME_FORMAT = current.TIME_FORMAT db = current.db T = current.T cls = Class(clsID, date) teID = self.get_linked_customer_id() teacher = Teacher(teID) default_rates = teacher.get_payment_fixed_rate_default() class_rates = teacher.get_payment_fixed_rate_classes_dict() if not default_rates and not class_rates: return None # No rates set, not enough data to create invoice item default_rate = default_rates.first() price = default_rate.ClassRate tax_rates_id = default_rate.tax_rates_id # Set price and tax rate try: class_prices = class_rates.get(int(clsID), False) if class_prices: price = class_prices.ClassRate tax_rates_id = class_prices.tax_rates_id except (AttributeError, KeyError): pass # add item to invoice next_sort_nr = self.get_item_next_sort_nr() iiID = db.invoices_items.insert( invoices_id=self.invoices_id, ProductName=T('Class'), Description=cls.get_name(), Quantity=1, Price=price * -1, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, ) self.set_amounts() self.on_update() return iiID
def item_add_teacher_class_attendance_credit_payment(self, tpcID): """ :param clsID: db.classes.id :param date: datetime.date class date :return: """ from os_class import Class from os_teacher import Teacher from os_teachers_payment_class import TeachersPaymentClass DATE_FORMAT = current.DATE_FORMAT TIME_FORMAT = current.TIME_FORMAT db = current.db T = current.T tpc = TeachersPaymentClass(tpcID) cls = Class( tpc.row.classes_id, tpc.row.ClassDate ) # Get amount & tax rate rate = tpc.row.ClassRate tax_rates_id = tpc.row.tax_rates_id tax_rate = db.tax_rates(tax_rates_id) if tax_rate: percentage = float(tax_rate.Percentage / 100) price = rate * (1 + percentage) else: price = rate # add item to invoice if price > 0: next_sort_nr = self.get_item_next_sort_nr() iiID = db.invoices_items.insert( invoices_id=self.invoices_id, ProductName=T('Class'), Description=cls.get_name(), Quantity=1, Price=price * -1, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, ) self.link_item_to_teachers_payment_class(tpcID, iiID) # This calls self.on_update() self.set_amounts() return iiID
def item_add_class_from_order(self, order_item_row, caID): """ Add class to invoice from Order.deliver() :param clsID: db.classes.id :param class_date: datetime.date :param attendance_type: int 1 or 2 :return: db.invoices_items.id """ from os_class import Class DATE_FORMAT = current.DATE_FORMAT TIME_FORMAT = current.TIME_FORMAT db = current.db T = current.T cls = Class(order_item_row.classes_id, order_item_row.ClassDate) # Get GLAccount info prices = cls.get_prices() glaccount = None if order_item_row.AttendanceType == 1: # Trial glaccount = prices['trial_glaccount'] else: # Drop in glaccount = prices['dropin_glaccount'] # add item to invoice next_sort_nr = self.get_item_next_sort_nr() iiID = db.invoices_items.insert( invoices_id=self.invoices_id, ProductName=order_item_row.ProductName, Description=order_item_row.Description, Quantity=order_item_row.Quantity, Price=order_item_row.Price, Sorting=next_sort_nr, tax_rates_id=order_item_row.tax_rates_id, accounting_glaccounts_id=order_item_row.accounting_glaccounts_id, accounting_costcenters_id=order_item_row.accounting_costcenters_id, ) self.link_item_to_classes_attendance( caID, iiID ) # This calls self.on_update() self.set_amounts() return iiID
def check_missing(self, date_from, date_until): """ :param date_from: :param date_until: :return: """ from date_tools import DateTools from os_class import Class from os_class_schedule import ClassSchedule T = current.T db = current.db dt = DateTools() error = False message = '' classes_added = 0 days_between = dt.days_between_dates(date_from, date_until) if days_between == False: error = True message = T("From date has to be smaller then until date.") if days_between > 92: error = True message = T("Gap between dates can not be more then 3 months") if not error: date = date_from while date <= date_until: cs = ClassSchedule(date) classes = cs.get_day_list() for cls in classes: if not cls['Cancelled'] or cls['Holiday']: # Check if item in db.teachers_payment_classes query = (db.teachers_payment_classes.classes_id == cls['ClassesID']) & \ (db.teachers_payment_classes.ClassDate == date) if db(query).count() == 0: os_cls = Class(cls['ClassesID'], date) result = os_cls.get_teacher_payment() if not result['error']: classes_added += 1 date += datetime.timedelta(days=1) message = classes_added return dict(error=error, message=message)
def order_item_add_class(self, clsID, class_date, attendance_type): """ :param workshops_products_id: db.workshops_products.id :return: db.customers_orders_items.id of inserted item """ from os_class import Class DATE_FORMAT = current.DATE_FORMAT TIME_FORMAT = current.TIME_FORMAT db = current.db T = current.T cls = Class(clsID, class_date) prices = cls.get_prices_customer(self.order.auth_customer_id) if attendance_type == 1: price = prices['trial'] tax_rates_id = prices['trial_tax_rates_id'] glaccount = prices['trial_glaccount'] costcenter = prices['trial_costcenter'] elif attendance_type == 2: price = prices['dropin'] tax_rates_id = prices['dropin_tax_rates_id'] glaccount = prices['dropin_glaccount'] costcenter = prices['dropin_costcenter'] description = cls.get_invoice_order_description(attendance_type) coiID = db.customers_orders_items.insert( customers_orders_id=self.coID, classes_id=clsID, AttendanceType=attendance_type, ClassDate=class_date, ProductName=T('Class'), Description=description, Quantity=1, Price=price, tax_rates_id=tax_rates_id, accounting_glaccounts_id=glaccount, accounting_costcenters_id=costcenter) self.set_amounts() return coiID
def get_classes_revenue_summary_day(self, date): """ :param date: :return: """ from os_class import Class from os_class_schedule import ClassSchedule # Get class schedule for days cs = ClassSchedule(date) schedule = cs.get_day_list() revenue = { 'data': [], 'revenue_total': 0, 'teacher_payments': 0, 'balance': 0 } for cls in schedule: clsID = cls['ClassesID'] # Get revenue for each class class_revenue = self.get_class_revenue_summary(clsID, date) cls_object = Class(clsID, date) teacher_payment = cls_object.get_teacher_payment() if not teacher_payment['error']: tp_amount = teacher_payment['data']['ClassRate'] else: tp_amount = 0 cls['RevenueTotal'] = class_revenue['total']['amount'] cls['TeacherPayment'] = tp_amount cls['Balance'] = (cls['RevenueTotal'] - cls['TeacherPayment']) revenue['revenue_total'] += cls['RevenueTotal'] revenue['teacher_payments'] += cls['TeacherPayment'] revenue['balance'] += cls['Balance'] revenue['data'].append(cls) return revenue
def _get_class_revenue_summary_pdf_template(self, clsID, date, quick_stats=True): """ Print friendly display of a Workshop """ from general_helpers import max_string_length from os_class import Class get_sys_property = current.globalenv['get_sys_property'] represent_float_as_amount = current.globalenv[ 'represent_float_as_amount'] response = current.response template = get_sys_property('branding_default_template_class_revenue' ) or 'class_revenue/default.html' template_file = 'templates/' + template tables = self.get_class_revenue_summary_formatted(clsID, date) cls = Class(clsID, date) teacher_payment = cls.get_teacher_payment() html = response.render( template_file, dict( class_info=cls.get_info(), revenue=self.get_class_revenue_summary(clsID, date, quick_stats), teacher_payment=teacher_payment, logo=self._get_class_revenue_summary_pdf_template_get_logo(), max_string_length=max_string_length, represent_float_as_amount=represent_float_as_amount, )) return html
def item_add_class_from_order(self, order_item_row, caID): """ Add class to invoice from Order.deliver() :param clsID: db.classes.id :param class_date: datetime.date :param attendance_type: int 1 or 2 :return: db.invoices_items.id """ from os_class import Class DATE_FORMAT = current.DATE_FORMAT TIME_FORMAT = current.TIME_FORMAT db = current.db T = current.T cls = Class(order_item_row.classes_id, order_item_row.ClassDate) # link invoice to attendance db.invoices_classes_attendance.insert(invoices_id=self.invoices_id, classes_attendance_id=caID) # add item to invoice next_sort_nr = self.get_item_next_sort_nr() iiID = db.invoices_items.insert( invoices_id=self.invoices_id, ProductName=order_item_row.ProductName, Description=order_item_row.Description, Quantity=order_item_row.Quantity, Price=order_item_row.Price, Sorting=next_sort_nr, tax_rates_id=order_item_row.tax_rates_id, ) self.set_amounts() self.on_update() return iiID
def item_add_class(self, cuID, caID, clsID, date, product_type): """ Add invoice item when checking in to a class :param cuID: db.auth_user.id :param caID: db.classes_attendance.id :param clsID: db.classes.id :param date: datetime.date (class date) :param product_type: has to be 'trial' or 'dropin' :return: """ from os_customer import Customer from os_class import Class db = current.db DATE_FORMAT = current.DATE_FORMAT T = current.T date_formatted = date.strftime(DATE_FORMAT) if product_type not in ['trial', 'dropin']: raise ValueError("Product type has to be 'trial' or 'dropin'.") customer = Customer(cuID) cls = Class(clsID, date) prices = cls.get_prices() has_membership = customer.has_membership_on_date(date) if product_type == 'dropin': price = prices['dropin'] tax_rates_id = prices['dropin_tax_rates_id'] glaccount = prices['dropin_glaccount'] costcenter = prices['dropin_costcenter'] if has_membership and prices['dropin_membership']: price = prices['dropin_membership'] tax_rates_id = prices['dropin_tax_rates_id_membership'] description = cls.get_invoice_order_description( 2) # 2 = drop in class elif product_type == 'trial': price = prices['trial'] tax_rates_id = prices['trial_tax_rates_id'] glaccount = prices['trial_glaccount'] costcenter = prices['trial_costcenter'] if has_membership and prices['trial_membership']: price = prices['trial_membership'] tax_rates_id = prices['trial_tax_rates_id_membership'] description = cls.get_invoice_order_description( 1) # 1 = trial class # link invoice to attendance self.link_to_classes_attendance(caID) next_sort_nr = self.get_item_next_sort_nr() iiID = db.invoices_items.insert(invoices_id=self.invoices_id, ProductName=T("Class"), Description=description, Quantity=1, Price=price, Sorting=next_sort_nr, tax_rates_id=tax_rates_id, accounting_glaccounts_id=glaccount, accounting_costcenters_id=costcenter) self.link_to_customer(cuID) # This calls self.on_update() self.set_amounts()
def get_class_revenue_summary(self, clsID, date, quick_stats=True): """ :param subscription_quick_stats: Boolean - use db.school_subscriptions.QuickStatsAmount or not :return: """ from os_class import Class cls = Class(clsID, date) class_prices = cls.get_prices() data = { 'subscriptions': {}, 'classcards': {}, 'dropin': { 'membership': { 'count': 0, 'amount': class_prices['dropin_membership'] }, 'no_membership': { 'count': 0, 'amount': class_prices['dropin'] } }, 'trial': { 'membership': { 'count': 0, 'amount': class_prices['trial_membership'] }, 'no_membership': { 'count': 0, 'amount': class_prices['trial'] } }, 'complementary': { 'count': 0, 'amount': 0 }, 'total': { 'count': 0, 'amount': 0 } } rows = self.get_class_revenue_rows(clsID, date) for i, row in enumerate(rows): repr_row = list(rows[i:i + 1].render())[0] ex_vat = 0 vat = 0 in_vat = 0 description = '' if row.classes_attendance.AttendanceType is None: # Subscription name = row.school_subscriptions.Name amount = row.school_subscriptions.QuickStatsAmount or 0 if data['subscriptions'].get(name, False): data['subscriptions'][name]['count'] += 1 data['subscriptions'][name]['total'] = \ data['subscriptions'][name]['count'] * amount else: data['subscriptions'][name] = { 'count': 1, 'total': amount, 'amount': amount } data['total']['amount'] += amount elif row.classes_attendance.AttendanceType == 1: # Trial if row.classes_attendance.CustomerMembership: data['trial']['membership']['count'] += 1 data['total']['amount'] += data['trial']['membership'][ 'amount'] else: data['trial']['no_membership']['count'] += 1 data['total']['amount'] += data['trial']['no_membership'][ 'amount'] elif row.classes_attendance.AttendanceType == 2: # Dropin if row.classes_attendance.CustomerMembership: data['dropin']['membership']['count'] += 1 data['total']['amount'] += data['dropin']['membership'][ 'amount'] else: data['dropin']['no_membership']['count'] += 1 data['total']['amount'] += data['dropin']['no_membership'][ 'amount'] elif row.classes_attendance.AttendanceType == 3: # Class card name = row.school_classcards.Name if not row.school_classcards.Unlimited: amount = row.school_classcards.Price / row.school_classcards.Classes else: revenue = get_class_revenue_classcard(row) amount = revenue['total_revenue_in_vat'] if data['classcards'].get(name, False): data['classcards'][name]['count'] += 1 data['classcards'][name]['total'] = \ data['classcards'][name]['count'] * amount else: data['classcards'][name] = { 'count': 1, 'total': amount, 'amount': amount } data['total']['amount'] += amount elif row.classes_attendance.AttendanceType == 4: # Complementary data['complementary']['count'] += 1 data['total']['count'] += 1 return data
def get_class_revenue_summary_formatted(self, clsID, date, quick_stats=True): """ Format output from self.get_class_revenue_summary :param clsID: db.classes.id :param date: datetime.date :param quickstats: boolean :return: html table """ from os_class import Class from general_helpers import max_string_length T = current.T represent_float_as_amount = current.globalenv[ 'represent_float_as_amount'] revenue = self.get_class_revenue_summary(clsID=clsID, date=date, quick_stats=quick_stats) header = THEAD( TR( TH(T('Type')), TH(T('Amount')), TH(T('Attendance count')), TH(T('Total')), )) trial_without_membership = TR( TD(T('Trial without membership')), TD( represent_float_as_amount( revenue['trial']['no_membership']['amount'])), TD(revenue['trial']['no_membership']['count']), TD( represent_float_as_amount( revenue['trial']['no_membership']['amount'] * revenue['trial']['no_membership']['count'])), ) trial_with_membership = TR( TD(T('Trial with membership')), TD( represent_float_as_amount( revenue['trial']['membership']['amount'])), TD(revenue['trial']['membership']['count']), TD( represent_float_as_amount( revenue['trial']['membership']['amount'] * revenue['trial']['membership']['count'])), ) dropin_without_membership = TR( TD(T('Drop-in without membership')), TD( represent_float_as_amount( revenue['dropin']['no_membership']['amount'])), TD(revenue['dropin']['no_membership']['count']), TD( represent_float_as_amount( revenue['dropin']['no_membership']['amount'] * revenue['dropin']['no_membership']['count'])), ) dropin_with_membership = TR( TD(T('Drop-in with membership')), TD( represent_float_as_amount( revenue['dropin']['membership']['amount'])), TD(revenue['dropin']['membership']['count']), TD( represent_float_as_amount( revenue['dropin']['membership']['amount'] * revenue['dropin']['membership']['count'])), ) table_revenue = TABLE(header, trial_without_membership, trial_with_membership, dropin_without_membership, dropin_with_membership, _class='table table-striped table-hover') # subscriptions for s in sorted(revenue['subscriptions']): amount = revenue['subscriptions'][s]['amount'] count = revenue['subscriptions'][s]['count'] table_revenue.append( TR(TD(max_string_length(s, 42)), TD(represent_float_as_amount(amount)), TD(count), TD(represent_float_as_amount(amount * count)))) # class cards for c in sorted(revenue['classcards']): amount = revenue['classcards'][c]['amount'] count = revenue['classcards'][c]['count'] table_revenue.append( TR(TD(max_string_length(c, 42)), TD(represent_float_as_amount(amount)), TD(count), TD(represent_float_as_amount(amount * count)))) # Complementary table_revenue.append( TR( TD(T('Complementary')), TD(), TD(revenue['complementary']['count']), TD(), )) # Total footer = TFOOT( TR( TH(T('Total')), TH(), TH(revenue['total']['count']), TH(represent_float_as_amount(revenue['total']['amount'])), )) table_revenue.append(footer) ## # table total ## cls = Class(clsID, date) teacher_payment = cls.get_teacher_payment() if not teacher_payment['error']: tp_amount = teacher_payment['data']['ClassRate'] tp_display = represent_float_as_amount(tp_amount) else: tp_amount = 0 tp_display = teacher_payment['data'] header = THEAD(TR( TH(T('Description')), TH(T('Amount')), )) attendance = TR( TD(T('Attendance')), TD(represent_float_as_amount(revenue['total']['amount']))) teacher_payment = TR(TD(T('Teacher payment')), TD(tp_display)) total = represent_float_as_amount(revenue['total']['amount'] - tp_amount) footer = TFOOT(TR(TH(T('Total')), TH(total))) table_total = TABLE(header, attendance, teacher_payment, footer, _class='table table-striped table-hover') return dict(table_revenue=table_revenue, table_total=table_total)
def get_subrequests_formatted(self): """ :return: HTML table holding subrequests this teacher can apply for """ from os_class import Class from os_gui import OsGui os_gui = OsGui() T = current.T db = current.db auth = current.auth TODAY_LOCAL = current.TODAY_LOCAL header = THEAD( TR(TH(T('Class date')), TH(T('Time')), TH(T('Location')), TH(T('Class type')), TH())) table = TABLE(header, _class='table table-hover') # Get classtypes for currently logged on teacher query = (db.teachers_classtypes.auth_user_id == self.id) rows = db(query).select(db.teachers_classtypes.school_classtypes_id) ctIDs = [row.school_classtypes_id for row in rows] left = [ db.classes.on(db.classes_otc.classes_id == db.classes.id, ), db.school_locations.on( db.classes.school_locations_id == db.school_locations.id) ] query = (db.classes_otc.Status == 'open') & \ ((db.classes.school_classtypes_id.belongs(ctIDs)) | (db.classes_otc.school_classtypes_id.belongs(ctIDs))) & \ (db.classes_otc.ClassDate >= TODAY_LOCAL) rows = db(query).select(db.classes_otc.ALL, db.classes.ALL, left=left, orderby=db.classes_otc.ClassDate | db.classes.Starttime | db.school_locations.Name) for i, row in enumerate(rows): repr_row = list(rows[i:i + 1].render())[0] row_avail = db.classes_otc_sub_avail( classes_otc_id=row.classes_otc.id, auth_teacher_id=auth.user.id) date = row.classes_otc.ClassDate clsID = row.classes.id cls = Class(clsID, date) regular_teachers = cls.get_regular_teacher_ids() if regular_teachers['auth_teacher_id'] == self.id: continue if not row_avail: button = os_gui.get_button( 'noicon', URL('ep', 'available_for_sub', vars={'cotcID': row.classes_otc.id}), title=T("I'm available"), _class='pull-right', btn_class='btn-success') else: button = os_gui.get_button('noicon', URL('ep', 'cancel_available_for_sub', vars={'cotcsaID': row_avail.id}), title=T("I'm no longer available"), _class='pull-right', btn_class='btn-warning') tr = TR( TD(repr_row.classes_otc.ClassDate), TD(repr_row.classes.Starttime, ' - ', repr_row.classes.Endtime), TD(repr_row.classes.school_locations_id), TD(repr_row.classes.school_classtypes_id), TD(button)) table.append(tr) if not len(rows): table = T("No one is looking for a sub at the moment...") sub_requests = DIV(DIV(H3(T('Can you sub a class?'), _class="box-title"), DIV(A(I(_class='fa fa-minus'), _href='#', _class='btn btn-box-tool', _title=T("Collapse"), **{'_data-widget': 'collapse'}), _class='box-tools pull-right'), _class='box-header with-border'), DIV(table, _class='box-body'), _class='box box-success') return sub_requests