Exemple #1
0
    def get_classcards(self, auth_user_id=None, public_only=True):
        """
            :param public_only: Defines whether or not to show only public classcards, True by default
                                False means all cards are returned
            Returns classcards for school
        """
        from tools import OsTools

        db = current.db
        os_tools = OsTools()

        allow_trial_for_existing_customers = os_tools.get_sys_property(
            'shop_allow_trial_cards_for_existing_customers')

        query = (db.school_classcards.Archived == False)
        if public_only:
            query &= (db.school_classcards.PublicCard == True)

        if auth_user_id and allow_trial_for_existing_customers != 'on':
            from os_customer import Customer

            customer = Customer(auth_user_id)
            has_or_had_subscription = customer.get_has_or_had_subscription()
            has_or_had_card = customer.get_has_or_had_classcard()

            if has_or_had_card or has_or_had_subscription:
                query &= (db.school_classcards.Trialcard == False)

        return db(query).select(db.school_classcards.ALL,
                                orderby=db.school_classcards.Trialcard
                                | db.school_classcards.Name)
    def create_bankaccount(self, os_customer, os_customer_payment_info):
        """
        :param os_customer: OsCustomer object
        :return: None
        """
        from exactonline.http import HTTPError
        from tools import OsTools

        os_tools = OsTools()
        authorized = os_tools.get_sys_property('exact_online_authorized')

        if not authorized:
            self._log_error('create', 'bankaccount', os_customer.row.id,
                            "Exact online integration not authorized")

            return

        api = self.get_api()
        eoID = os_customer.row.exact_online_relation_id

        bank_account_dict = {
            'Account': eoID,
            'BankAccount': os_customer_payment_info.row.AccountNumber,
            'BankAccountHolderName':
            os_customer_payment_info.row.AccountHolder,
            'BICCode': os_customer_payment_info.row.BIC
        }

        eo_bankaccount_id = None

        # print "bank account creation result:"
        # result = api.bankaccounts.create(bank_account_dict)
        #
        # import pprint
        # pp = pprint.PrettyPrinter(depth=6)
        # pp.pprint(result)
        #
        # eo_bankaccount_id = result['ID']
        # os_customer_payment_info.row.exact_online_bankaccount_id = eo_bankaccount_id
        # os_customer_payment_info.row.update_record()

        try:
            result = api.bankaccounts.create(bank_account_dict)

            # print "bank account creation result:"
            # import pprint
            # pp = pprint.PrettyPrinter(depth=6)
            # pp.pprint(result)

            eo_bankaccount_id = result['ID']
            os_customer_payment_info.row.exact_online_bankaccount_id = eo_bankaccount_id
            os_customer_payment_info.row.update_record()

        except HTTPError as e:
            error = True
            self._log_error('create', 'bankaccount',
                            os_customer_payment_info.row.id, e)

        return eo_bankaccount_id
Exemple #3
0
    def _get_formatted_button_apply_accent_color(self, a):
        from tools import OsTools

        os_tools = OsTools()
        color = os_tools.get_sys_property(
            'shop_branding_secondary_accent_color')

        if color:
            a['_style'] = 'color: %s;' % (color)
        else:
            a['_class'] = ''

        return a
    def create_dd_mandate(self, os_customer_payment_info, os_cpim):
        """
        :param os_customer_payment_info: payment info object
        :param os_cpim: payment info mandates object
        :return:
        """
        from exactonline.http import HTTPError
        from tools import OsTools
        from os_customer import Customer

        TODAY_LOCAL = current.TODAY_LOCAL
        os_tools = OsTools()
        authorized = os_tools.get_sys_property('exact_online_authorized')

        if not authorized:
            self._log_error('create', 'directdebitmandate', os_cpim.cpimID,
                            "Exact online integration not authorized")

            return

        api = self.get_api()

        customer = Customer(os_customer_payment_info.row.auth_customer_id)
        eoID = customer.row.exact_online_relation_id
        if not eoID:
            eoID = self.create_relation(customer)

        eo_bankaccount_id = os_customer_payment_info.row.exact_online_bankaccount_id

        # print os_customer_payment_info.row

        if not eo_bankaccount_id:
            eo_bankaccount_id = self.create_bankaccount(
                customer, os_customer_payment_info)

        mandate_dict = {
            'Account': eoID,
            'BankAccount': eo_bankaccount_id,
            'Reference': os_cpim.row.MandateReference,
            'SignatureDate': TODAY_LOCAL.strftime("%Y-%m-%d")
        }

        try:
            result = api.directdebitmandates.create(mandate_dict)
            os_cpim.row.exact_online_directdebitmandates_id = result['ID']
            os_cpim.row.update_record()

        except HTTPError as e:
            error = True
            self._log_error('create', 'mandate',
                            os_customer_payment_info.cpiID, e)
Exemple #5
0
    def exact_online_sync_invoices(self):
        """
        Due to a timeout in tokens, sometimes invoices don't sync immediately, as a API request
        seems to be used to aquire a new token. This function can be run every 15 minutes for
        example to sync all unsynced invoices
        :return: None
        """
        from tools import OsTools
        from os_invoice import Invoice

        T = current.T
        db = current.db

        count_synced = 0
        count_errors = 0

        os_tools = OsTools()
        eo_authorized = os_tools.get_sys_property('exact_online_authorized')


        if eo_authorized == 'True':
            from os_exact_online import OSExactOnline

            os_eo = OSExactOnline()

            query = (db.invoices.ExactOnlineSalesEntryID == None)
            rows = db(query).select(db.invoices.ALL)
            for row in rows:
                invoice = Invoice(row.id)

                if not invoice.invoice_group.JournalID:
                    os_eo._log_error(
                        'update',
                        'invoice',
                        invoice.invoices_id,
                        'No JournalID specified for invoice group'
                    )
                    count_errors += 1
                else:
                    error = os_eo.update_sales_entry(invoice)
                    if error:
                        count_errors += 1
                    else:
                        count_synced += 1

        return T("m_openstudio_os_scheduler_tasks_exact_online_sync_invoices_return") + ': (' + \
               unicode(count_synced) + ' / ' + \
               unicode(count_errors) + ')'
Exemple #6
0
    def _get_formatted_display_widget_header(self, name, price):
        from tools import OsTools

        os_tools = OsTools()
        bg_color = os_tools.get_sys_property(
            'shop_branding_primary_accent_bg_color')
        fg_color = os_tools.get_sys_property(
            'shop_branding_primary_accent_fg_color')

        header = DIV(H3(name, _class="widget-user-username"),
                     H4(price, _class="widget-user-desc"),
                     _class="widget-user-header")

        if bg_color and fg_color:
            header['_style'] = 'background: %s; color: %s;' % (bg_color,
                                                               fg_color)

        return header
    def get_pauses_count_gt_max_pauses_in_year(self, year):
        """

        :param year: int
        :return:
        """
        from tools import OsTools

        os_tools = OsTools()
        max_pauses_in_year = os_tools.get_sys_property('subscription_max_pauses')

        if not max_pauses_in_year:
            # Return False by default when setting is not defined
            return False

        count_pauses_in_year = self.get_pauses_count_in_year(year)
        if count_pauses_in_year > int(max_pauses_in_year):
            return True
        else:
            return False
Exemple #8
0
    def update_bankaccount(self, os_customer, os_customer_payment_info):
        """
        :param os_customer: OsCustomer object
        :return: None
        """
        from exactonline.http import HTTPError
        from tools import OsTools

        os_tools = OsTools()
        authorized = os_tools.get_sys_property('exact_online_authorized')

        if not authorized:
            self._log_error('update', 'bankaccount', os_customer.row.id,
                            "Exact online integration not authorized")

            return

        api = self.get_api()
        eoID = os_customer.row.exact_online_relation_id

        exact_account = self.get_bankaccount(os_customer)
        if not len(exact_account):
            self.create_bankaccount(os_customer, os_customer_payment_info)

        bank_account_dict = {
            'Account': eoID,
            'BankAccount': os_customer_payment_info.row.AccountNumber,
            'BankAccountHolderName':
            os_customer_payment_info.row.AccountHolder,
            'BICCode': os_customer_payment_info.row.BIC
        }

        try:
            # print 'actually updating account'
            # print os_customer_payment_info.row.exact_online_bankaccount_id
            api.bankaccounts.update(
                os_customer_payment_info.row.exact_online_bankaccount_id,
                bank_account_dict)
        except HTTPError as e:
            error = True
            self._log_error('update', 'bankaccount', os_customer.row.id, e)
Exemple #9
0
    def on_update(self):
        """
        functions to be called when updating an invoice or invoice items
        """
        from tools import OsTools
        from os_exact_online import OSExactOnline

        os_tools = OsTools()
        eo_authorized = os_tools.get_sys_property('exact_online_authorized')

        # Set last updated datetime
        self._set_updated_at()

        # Exact online integration
        if eo_authorized == 'True':
            os_eo = OSExactOnline()
            if not self.invoice_group.JournalID:
                os_eo._log_error('update', 'invoice', self.invoices_id,
                                 'No JournalID specified for invoice group')
            else:
                os_eo.update_sales_entry(self)
Exemple #10
0
    def get_pause_gte_min_duration(self):
        """
        :return: True if >= min pause length
        """
        from tools import OsTools

        os_tools = OsTools()
        min_duration = os_tools.get_sys_property(
            'subscription_pauses_min_duration')

        if not min_duration:
            # Return True when min duration is not defined
            return True

        min_duration = int(min_duration)
        delta = self.row.Enddate - self.row.Startdate
        pause_duration = delta.days

        if pause_duration >= min_duration:
            return True
        else:
            return False
Exemple #11
0
    def log_subscription_terms_acceptance(self, school_subscriptions_id):
        """
        :param school_subscriptions_id: db.school_subscriptions.id
        :return: None
        """
        from os_school_subscription import SchoolSubscription
        from tools import OsTools

        T = current.T
        os_tools = OsTools()
        ssu = SchoolSubscription(school_subscriptions_id, set_db_info=True)

        terms = [
            os_tools.get_sys_property('shop_subscriptions_terms')
            or '',  # general terms
            ssu.Terms or ''  # Subscription specific terms
        ]
        full_terms = '\n'.join(terms)

        self.log_document_acceptance(
            document_name=T("Subscription terms"),
            document_description=T(
                "Terms for all subscriptions and subscription specific terms"),
            document_content=full_terms)
Exemple #12
0
    def log_membership_terms_acceptance(self, school_memberships_id):
        """
        :param school_memberships_id: db.school_memberships.id
        :return: None
        """
        from os_school_membership import SchoolMembership
        from tools import OsTools

        T = current.T
        os_tools = OsTools()
        sm = SchoolMembership(school_memberships_id)

        terms = [
            os_tools.get_sys_property('shop_memberships_terms')
            or '',  # general terms
            sm.row.Terms or ''  # membership specific terms
        ]
        full_terms = '\n'.join(terms)

        self.log_document_acceptance(
            document_name=T("Membership terms"),
            document_description=T(
                "Terms for all memberships and membership specific terms"),
            document_content=full_terms)
    def update_sales_entry(self, os_invoice):
        """
        :param os_customer: OsCustomer object
        :return: None
        """
        from exactonline.resource import GET

        from os_customer import Customer
        from tools import OsTools

        os_tools = OsTools()
        authorized = os_tools.get_sys_property('exact_online_authorized')

        if not authorized:
            self._log_error('update', 'sales_entry', os_invoice.invoice.id,
                            "Exact online integration not authorized")

            return

        items = os_invoice.get_invoice_items_rows()
        if not len(items):
            return  # Don't do anything for invoices without items

        eoseID = os_invoice.invoice.ExactOnlineSalesEntryID

        if not eoseID:
            self.create_sales_entry(os_invoice)
            return

        import pprint

        from ConfigParser import NoOptionError
        from exactonline.http import HTTPError

        storage = self.get_storage()
        api = self.get_api()
        cuID = os_invoice.get_linked_customer_id()
        os_customer = Customer(os_invoice.get_linked_customer_id())

        try:
            selected_division = int(storage.get('transient', 'division'))
        except NoOptionError:
            selected_division = None

        amounts = os_invoice.get_amounts()

        remote_journal = os_invoice.invoice_group.JournalID
        invoice_date = os_invoice.invoice.DateCreated
        is_credit_invoice = os_invoice.is_credit_invoice()
        local_invoice_number = os_invoice.invoice.id
        payment_method = os_invoice.get_payment_method()

        invoice_data = {
            'AmountDC': str(amounts.TotalPriceVAT),  # DC = default currency
            'AmountFC': str(amounts.TotalPriceVAT),  # FC = foreign currency
            'EntryDate': invoice_date.strftime(
                '%Y-%m-%dT%H:%M:%SZ'),  # pretend we're in UTC
            'Customer': os_customer.row.exact_online_relation_id,
            'Description': os_invoice.invoice.Description,
            'Journal': remote_journal,  # 70 "Verkoopboek"
            'ReportingPeriod': invoice_date.month,
            'ReportingYear': invoice_date.year,
            'VATAmountDC': str(amounts.VAT),
            'VATAmountFC': str(amounts.VAT),
            'YourRef': local_invoice_number,
        }

        if payment_method and payment_method.AccountingCode:
            invoice_data['PaymentCondition'] = payment_method.AccountingCode

        if is_credit_invoice:
            invoice_data['Type'] = 21

        error = False

        try:
            result = api.invoices.update(eoseID, invoice_data)
            # print "Update invoice result:"
            # pp = pprint.PrettyPrinter(depth=6)
            # pp.pprint(result)

            self.update_sales_entry_lines(os_invoice)

        except HTTPError as e:
            error = True
            self._log_error('create', 'sales_entry', os_invoice.invoice.id, e)

        if error:
            return False
Exemple #14
0
    def _get_print_display_format_items(self):
        """
        :param items: gluon.dal.rows object of db.receipts_items
        :return: html table
        """
        from tools import OsTools

        T = current.T
        db = current.db
        os_tools = OsTools()
        currency = os_tools.get_sys_property('Currency')
        amounts_total = self.get_amounts()
        amounts_vat = self.get_amounts_tax_rates()

        items_header = THEAD(
            TR(
                TH(T("Product")),
                TH(T("Qty")),
                TH(T("Total"), _class="header-total"),
            ))
        table = TABLE(items_header)

        for item in self.get_receipt_items_rows():
            table.append(
                TR(
                    TD(item.ProductName, BR(),
                       SPAN(item.Description, _class='item-description')),
                    TD(item.Quantity), TD(format(item.TotalPriceVAT, ".2f"))))

        items_footer = TFOOT()

        amounts = [[T('Total'), amounts_total.TotalPriceVAT]]

        for tax_rate in amounts_vat:
            amounts.append([tax_rate['Name'], tax_rate['Amount']])

        amounts.append([T('Sub total'), amounts_total.TotalPrice])

        for i, amount in enumerate(amounts):
            if i == 0:
                celltype = TH
            else:
                celltype = TD
            items_footer.append(
                TR(
                    celltype(amount[0], _class='bold'),
                    celltype(currency),
                    celltype(
                        SPAN(format(amount[1], '.2f'),
                             _class='bold pull-right')),
                ))

        # Payment method
        pm = db.payment_methods(self.row.payment_methods_id)

        items_footer.append(
            TR(TD(T("Payment method")), TD(pm.Name, _colspan="2")))

        table.append(items_footer)

        return table
Exemple #15
0
    def get_memberships_formatted(self,
                                  per_row=3,
                                  public_only=True,
                                  link_type='shop'):
        """
            :param public: boolean, defines whether to show only public or all memberships
            :return: list of school_memberships formatted for shop
        """
        from openstudio.tools import OsTools
        from openstudio.os_school_membership import SchoolMembership

        os_gui = current.globalenv['os_gui']
        T = current.T
        os_tools = OsTools()
        TODAY_LOCAL = current.TODAY_LOCAL

        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_memberships(public_only=public_only)

        memberships = DIV()
        display_row = DIV(_class='row')
        row_item = 0

        for i, row in enumerate(rows):
            repr_row = list(rows[i:i + 1].render())[0]

            sm = SchoolMembership(row.id)
            name = max_string_length(row.Name, 33)

            validity = os_tools.format_validity(row.Validity, row.ValidityUnit)

            membership = DIV(
                DIV(
                    DIV(
                        self._get_formatted_display_widget_header(
                            name, repr_row.Price)),
                    DIV(DIV(repr_row.Description, _class='col-md-12'),
                        _class='box-body'),
                    DIV(
                        DIV(
                            DIV(DIV(H5(validity, _class="description-header"),
                                    SPAN(T("Validity"),
                                         _class="description-text"),
                                    _class="description-block"),
                                _class="col-sm-6 border-right"),
                            # DIV(
                            #     DIV(H5(repr_row.Classes,
                            #             _class="description-header"),
                            #         SPAN(T("Classes"), _class="description-text"),
                            #         _class="description-block"
                            #     ),
                            #     _class="col-sm-4 border-right"
                            # ),
                            DIV(DIV(H5(
                                self._get_memberships_formatted_button_to_cart(
                                    row.id),
                                _class="description-header"),
                                    SPAN(T(""), _class="description-text"),
                                    _class="description-block"),
                                _class="col-sm-6"),
                            _class="row"),
                        _class="box-footer",
                    ),
                    _class="box box-widget widget-user"),
                _class=card_class)

            # membership_content = TABLE(TR(TD(T('Validity')),
            #                               TD(validity)),
            #                            TR(TD(T('Price')),
            #                               TD(sm.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_memberships_formatted_button_to_cart(row.id)
            #
            # membership = DIV(os_gui.get_box_table(
            #     name,
            #     membership_content,
            #     panel_class,
            #     show_footer=True,
            #     footer_content=footer_content),
            #     _class=card_class)

            display_row.append(membership)

            row_item += 1

            if row_item == per_row or i == (len(rows) - 1):
                memberships.append(display_row)
                display_row = DIV(_class='row')
                row_item = 0

        return memberships
    def create_sales_entry(self, os_invoice):
        """
        :param os_customer: OsCustomer object
        :param os_invoice: OsInvoice Object
        :return:
        """
        from exactonline.resource import GET
        from os_customer import Customer
        from tools import OsTools

        db = current.db
        os_tools = OsTools()
        authorized = os_tools.get_sys_property('exact_online_authorized')

        if not authorized:
            self._log_error('create', 'sales_entry', os_invoice.invoice.id,
                            "Exact online integration not authorized")

            return

        items = os_invoice.get_invoice_items_rows()
        if not len(items):
            return  # Don't do anything for invoices without items

        import pprint

        from ConfigParser import NoOptionError
        from exactonline.http import HTTPError

        storage = self.get_storage()
        api = self.get_api()
        cuID = os_invoice.get_linked_customer_id()
        os_customer = Customer(os_invoice.get_linked_customer_id())
        eoID = os_customer.row.exact_online_relation_id

        if not eoID:
            self._log_error(
                'create', 'sales_entry', os_invoice.invoice.id,
                "This customer is not linked to Exact Online - " +
                unicode(os_customer.row.id))
            return

        try:
            selected_division = int(storage.get('transient', 'division'))
        except NoOptionError:
            selected_division = None

        amounts = os_invoice.get_amounts()

        remote_journal = os_invoice.invoice_group.JournalID
        invoice_date = os_invoice.invoice.DateCreated
        is_credit_invoice = os_invoice.is_credit_invoice()
        local_invoice_number = os_invoice.invoice.id
        payment_method = os_invoice.get_payment_method()

        invoice_data = {
            'AmountDC': str(amounts.TotalPriceVAT),  # DC = default currency
            'AmountFC': str(amounts.TotalPriceVAT),  # FC = foreign currency
            'EntryDate': invoice_date.strftime(
                '%Y-%m-%dT%H:%M:%SZ'),  # pretend we're in UTC
            'Customer': eoID,
            'Description': os_invoice.invoice.Description,
            'Journal': remote_journal,  # 70 "Verkoopboek"
            'ReportingPeriod': invoice_date.month,
            'ReportingYear': invoice_date.year,
            'SalesEntryLines': self.format_os_sales_entry_lines(os_invoice),
            'VATAmountDC': str(amounts.VAT),
            'VATAmountFC': str(amounts.VAT),
            'YourRef': local_invoice_number,
        }

        if payment_method and payment_method.AccountingCode:
            invoice_data['PaymentCondition'] = payment_method.AccountingCode

        if is_credit_invoice:
            invoice_data['Type'] = 21

        error = False

        try:
            result = api.invoices.create(invoice_data)
            #
            # print "Create invoice result:"
            # pp = pprint.PrettyPrinter(depth=6)
            # pp.pprint(result)

            eoseID = result['EntryID']
            os_invoice.invoice.ExactOnlineSalesEntryID = eoseID
            os_invoice.invoice.InvoiceID = result['EntryNumber']
            os_invoice.invoice.update_record()

            uri = result[u'SalesEntryLines'][u'__deferred']['uri']
            entry_lines = api.restv1(GET(str(uri)))
            # pp.pprint(entry_lines)

            for i, line in enumerate(entry_lines):
                query = (db.invoices_items.invoices_id == os_invoice.invoice.id) & \
                        (db.invoices_items.Sorting == i + 1)
                db(query).update(ExactOnlineSalesEntryLineID=line['ID'])

        except HTTPError as e:
            error = True
            self._log_error('create', 'sales_entry', os_invoice.invoice.id, e)

        if error:
            return False

        return eoseID
    def update_relation(self, os_customer):
        """
        :param os_customer: OsCustomer object
        :return: dict(error=True|False, message='')
        """
        from tools import OsTools

        os_tools = OsTools()
        authorized = os_tools.get_sys_property('exact_online_authorized')

        if not authorized:
            self._log_error('create', 'relation', os_customer.row.id,
                            "Exact online integration not authorized")

            return

        eoID = os_customer.row.exact_online_relation_id

        if not eoID:
            self.create_relation(os_customer)
            return

        import pprint

        from ConfigParser import NoOptionError
        from exactonline.http import HTTPError

        storage = self.get_storage()
        api = self.get_api()

        try:
            selected_division = int(storage.get('transient', 'division'))
        except NoOptionError:
            selected_division = None

        relation_dict = {
            "AddressLine1": os_customer.row.address,
            "Name": os_customer.row.display_name,
            "ChamberOfCommerce": os_customer.row.company_registration,
            "City": os_customer.row.city,
            "Code": os_customer.row.id,
            "Country": os_customer.row.country,
            "Email": os_customer.row.email,
            "Phone": os_customer.row.phone,
            "Postcode": os_customer.row.postcode,
            "Status": "C",  # Customer
            "VATNumber": os_customer.row.company_tax_registration,
            "Website": os_customer.row.teacher_website
        }

        error = False
        message = ''

        try:
            result = api.relations.update(eoID, relation_dict)
        except HTTPError as e:
            error = True
            message = e

            self._log_error('update', 'relation', os_customer.row.id, e)

        return dict(error=error, message=message)