Esempio n. 1
0
    def _list_invoices_get_balance(self, row):
        """
            Retuns the balance for an invoice
        """
        from os_invoice import Invoice

        iID = row.invoices.id
        invoice = Invoice(iID)

        return invoice.get_balance(formatted=True)
Esempio n. 2
0
    def get_class_revenue_classcard(self, row):
        """
            :param row: row from db.classes_attendance with left join on db.customers_subscriptions
            :return: Revenue for class taken on a card
        """
        db = current.db

        from os_customer_classcard import CustomerClasscard
        from os_invoice import Invoice

        ccdID = row.classes_attendance.customers_classcards_id
        classcard = CustomerClasscard(ccdID)

        left = [
            db.invoices_items.on(db.invoices_items_customers_classcards.
                                 invoices_items_id == db.invoices_items.id)
        ]
        query = (db.invoices_items_customers_classcards.customers_classcards_id
                 == ccdID)
        rows = db(query).select(db.invoices_items.ALL, left=left)

        if not rows:
            revenue_in_vat = 0
            revenue_ex_vat = 0
            revenue_vat = 0
        else:
            row = rows.first()
            invoice = Invoice(row.invoices_id)
            amounts = invoice.get_amounts()

            price_in_vat = amounts.TotalPriceVAT
            price_ex_vat = amounts.TotalPrice

            # Divide by classes taken on card
            if classcard.unlimited:
                # Count all classes taken on card
                query = (
                    db.classes_attendance.customers_classcards_id == ccdID)
                count_classes = db(query).count()

                revenue_in_vat = price_in_vat / count_classes
                revenue_ex_vat = price_ex_vat / count_classes
                revenue_vat = revenue_in_vat - revenue_ex_vat
            else:
                revenue_in_vat = price_in_vat / classcard.classes
                revenue_ex_vat = price_ex_vat / classcard.classes
                revenue_vat = revenue_in_vat - revenue_ex_vat

        return dict(revenue_in_vat=revenue_in_vat,
                    revenue_ex_vat=revenue_ex_vat,
                    revenue_vat=revenue_vat)
    def sell_to_customer(self, cuID, waitinglist=False, invoice=True):
        """
            Sells a workshop to a customer and creates an invoice
            Creates an invoice when a workshop product is sold
        """
        from os_mail import OsMail
        from os_workshop import Workshop
        from os_invoice import Invoice

        db = current.db
        T = current.T

        info = False
        if self.workshop.AutoSendInfoMail:
            info = True

        wspID = self.wspID
        wspcID = db.workshops_products_customers.insert(
            auth_customer_id=cuID,
            workshops_products_id=wspID,
            Waitinglist=waitinglist,
            WorkshopInfo=info)

        ##
        # Add invoice
        ##
        if invoice and not waitinglist and self.price > 0:
            igpt = db.invoices_groups_product_types(ProductType='wsp')

            description = self.workshop_name + ' - ' + self.name

            iID = db.invoices.insert(
                invoices_groups_id=igpt.invoices_groups_id,
                Description=description,
                Status='sent'
            )

            # create object to set Invoice# and due date
            invoice = Invoice(iID)
            invoice.link_to_customer(cuID)
            invoice.item_add_workshop_product(wspcID)
            invoice.set_amounts()

        ##
        # Send info mail to customer if we have some practical info
        ##
        if self.workshop.AutoSendInfoMail and not waitinglist:
            osmail = OsMail()
            msgID = osmail.render_email_template('workshops_info_mail', workshops_products_customers_id=wspcID)
            osmail.send_and_archive(msgID, cuID)

        if not waitinglist:
            # Check if sold out
            if self.is_sold_out():
                # Cancel all unpaid orders with a sold out product for this workshop
                ws = Workshop(self.wsID)
                ws.cancel_orders_with_sold_out_products()

        return wspcID
Esempio n. 4
0
    def add_get_form(self, cuID, csID=None, cmID=None, full_width=True):
        """
            Returns add form for an invoice
        """
        from os_customer import Customer
        from os_invoice import Invoice

        self._add_get_form_permissions_check()

        db = current.db
        T = current.T

        customer = Customer(cuID)
        self._add_get_form_set_default_values_customer(customer)
        self._add_get_form_enable_minimal_fields()
        if csID:
            self._add_get_form_enable_subscription_fields(csID)

        form = SQLFORM(db.invoices, formstyle='bootstrap3_stacked')

        elements = form.elements('input, select, textarea')
        for element in elements:
            element['_form'] = "invoice_add"

        form_element = form.element('form')
        form['_id'] = 'invoice_add'

        if form.process().accepted:
            iID = form.vars.id
            invoice = Invoice(
                iID
            )  # This sets due date and Invoice (calls invoice.on_create() #
            invoice.link_to_customer(cuID)
            self._add_reset_list_status_filter()

            if csID:
                iiID = invoice.item_add_subscription(
                    csID, form.vars.SubscriptionYear,
                    form.vars.SubscriptionMonth)

            redirect(URL('invoices', 'edit', vars={'iID': iID}))

        # So the grids display the fields normally
        for field in db.invoices:
            field.readable = True

        return form
Esempio n. 5
0
    def sell_to_customer_create_invoice(self, ccdID):
        """
            Add an invoice after adding a classcard
        """
        from os_customer_classcard import CustomerClasscard
        from os_invoice import Invoice

        db = current.db
        T = current.T

        classcard = CustomerClasscard(ccdID)

        igpt = db.invoices_groups_product_types(ProductType='classcard')

        iID = db.invoices.insert(
            invoices_groups_id=igpt.invoices_groups_id,
            Description=classcard.get_name(),
            Status='sent'
        )

        # create object to set Invoice# and due date
        invoice = Invoice(iID)

        # link invoice to customer
        invoice.link_to_customer(classcard.get_auth_customer_id())

        # add classcard item
        invoice.item_add_classcard(ccdID)
Esempio n. 6
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) + ')'
    def process_accepted(self):
        """
        Create credit invoices for verified classes
        :return:
        """
        from os_invoice import Invoice
        from os_employee_claim import EmployeeClaim

        T = current.T
        db = current.db

        # Sort verified classes by employee
        rows = self.get_rows(status='accepted',
                             sorting='employee',
                             formatted=False,
                             all=True)

        # previous_teacher = None
        # current_teacher = None
        processed = 0
        invoices_created = 0
        # For each employee, create credit invoice and add all accepted claims
        for i, row in enumerate(rows):
            epID = row.employee_claims.auth_user_id
            if i == 0 or not previous_employee == epID:
                current_employee = epID

                igpt = db.invoices_groups_product_types(
                    ProductType='employee_expenses')
                iID = db.invoices.insert(
                    invoices_groups_id=igpt.invoices_groups_id,
                    EmployeeClaim=True,
                    Description=T('Expenses'),
                    Status='sent')

                invoice = Invoice(iID)
                invoice.link_to_customer(epID)

                invoices_created += 1

            ecID = row.employee_claims.id
            invoice.item_add_employee_claim_credit_payment(ecID)

            # Set status processed
            ec = EmployeeClaim(ecID)
            ec.set_status_processed()

            previous_employee = current_employee
            processed += 1

        # Calculate total

        return processed
Esempio n. 8
0
    def sell_to_customer_create_invoice(self, ccdID):
        """
            Add an invoice after adding a classcard
        """
        from os_customer_classcard import CustomerClasscard
        from os_invoice import Invoice

        db = current.db
        T = current.T

        classcard = CustomerClasscard(ccdID)

        igpt = db.invoices_groups_product_types(ProductType='classcard')

        iID = db.invoices.insert(invoices_groups_id=igpt.invoices_groups_id,
                                 Description=classcard.get_name(),
                                 Status='sent')

        # link invoice to classcard
        db.invoices_customers_classcards.insert(invoices_id=iID,
                                                customers_classcards_id=ccdID)

        # create object to set Invoice# and due date
        invoice = Invoice(iID)
        next_sort_nr = invoice.get_item_next_sort_nr()

        price = classcard.price

        iiID = db.invoices_items.insert(
            invoices_id=iID,
            ProductName=T("Class card"),
            Description=T("Class card") + ' ' + unicode(ccdID),
            Quantity=1,
            Price=price,
            Sorting=next_sort_nr,
            tax_rates_id=classcard.school_classcard.tax_rates_id,
        )

        invoice.set_amounts()
        invoice.link_to_customer(classcard.get_auth_customer_id())
    def process_verified(self, date_from=None, date_until=None):
        """
        Create credit invoices for verified classes
        :return:
        """
        from os_invoice import Invoice
        from os_teachers_payment_class import TeachersPaymentClass

        T = current.T
        db = current.db

        # Sort verified classes by teacher
        rows = self.get_rows(status='verified',
                             sorting='teacher',
                             formatted=False,
                             date_from=date_from,
                             date_until=date_until,
                             all=True)

        previous_teacher = None
        current_teacher = None
        processed = 0
        invoices_created = 0
        # For each teacher, create credit invoice and add all verified classes
        for i, row in enumerate(rows):
            teID = row.teachers_payment_classes.auth_teacher_id
            if i == 0 or not previous_teacher == teID:
                current_teacher = teID

                igpt = db.invoices_groups_product_types(
                    ProductType='teacher_payments')
                iID = db.invoices.insert(
                    invoices_groups_id=igpt.invoices_groups_id,
                    TeacherPayment=True,
                    Description=T('Classes'),
                    Status='sent')

                invoice = Invoice(iID)
                invoice.link_to_customer(teID)

                invoices_created += 1

            tpcID = row.teachers_payment_classes.id
            invoice.item_add_teacher_class_attendance_credit_payment(tpcID)

            # Add travel allowance
            if row.teachers_payment_classes.TravelAllowance:
                invoice.item_add_teacher_class_credit_travel_allowance(
                    row.teachers_payment_classes.classes_id,
                    row.teachers_payment_classes.ClassDate,
                    row.teachers_payment_classes.TravelAllowance,
                    row.teachers_payment_classes.tax_rates_id_travel_allowance)

            # Set status processed
            tpc = TeachersPaymentClass(tpcID)
            tpc.set_status_processed()

            previous_teacher = current_teacher
            processed += 1

        # Calculate total

        return processed
Esempio n. 10
0
    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)
Esempio n. 11
0
    def deliver(self,
                class_online_booking=True,
                class_booking_status='booked'):
        """
            Create invoice for order and deliver goods
        """
        from os_attendance_helper import AttendanceHelper
        from os_cache_manager import OsCacheManager
        from os_invoice import Invoice
        from os_school_classcard import SchoolClasscard
        from os_school_subscription import SchoolSubscription
        from os_customer_subscription import CustomerSubscription
        from os_school_membership import SchoolMembership
        from os_customer_membership import CustomerMembership
        from os_workshop import Workshop
        from os_workshop_product import WorkshopProduct

        cache_clear_classschedule_api = current.globalenv[
            'cache_clear_classschedule_api']
        get_sys_property = current.globalenv['get_sys_property']
        TODAY_LOCAL = current.TODAY_LOCAL
        ocm = OsCacheManager()
        db = current.db
        T = current.T

        if self.order.Status == 'delivered':
            return

        create_invoice = False
        iID = None
        invoice = None
        # Only create an invoice if order amount > 0
        amounts = self.get_amounts()

        sys_property_create_invoice = 'shop_donations_create_invoice'
        create_invoice_for_donations = get_sys_property(
            sys_property_create_invoice)
        if create_invoice_for_donations == 'on':
            create_invoice_for_donations = True
        else:
            create_invoice_for_donations = False

        if amounts:
            if amounts.TotalPriceVAT > 0:
                if not self.order.Donation or (self.order.Donation and
                                               create_invoice_for_donations):
                    create_invoice = True

                    # Create blank invoice
                    igpt = db.invoices_groups_product_types(ProductType='shop')

                    iID = db.invoices.insert(
                        invoices_groups_id=igpt.invoices_groups_id,
                        Description=T('Order #') + unicode(self.coID),
                        Status='sent')

                    # Link invoice to order
                    db.invoices_customers_orders.insert(
                        customers_orders_id=self.coID, invoices_id=iID)

                    # Call init function for invoices to set Invoice # , etc.
                    invoice = Invoice(iID)
                    invoice.link_to_customer(self.order.auth_customer_id)

        # Add items to the invoice
        rows = self.get_order_items_rows()

        for row in rows:
            ##
            # Only rows where school_classcards_id, workshops_products_id , classes_id or Donation are set
            # are put on the invoice
            ##

            # Check for product:
            if row.ProductVariant:
                if create_invoice:
                    invoice.item_add_product_variant(
                        product_name=row.ProductName,
                        description=row.Description,
                        quantity=row.Quantity,
                        price=row.Price,
                        tax_rates_id=row.tax_rates_id,
                        accounting_glaccounts_id=row.accounting_glaccounts_id,
                        accounting_costcenters_id=row.accounting_costcenters_id
                    )

            # Check for classcard
            if row.school_classcards_id:
                # Deliver card
                card_start = TODAY_LOCAL
                scd = SchoolClasscard(row.school_classcards_id)
                ccdID = scd.sell_to_customer(self.order.auth_customer_id,
                                             card_start,
                                             invoice=False)

                # clear cache
                ocm.clear_customers_classcards(self.order.auth_customer_id)

                # Add card to invoice
                if create_invoice:
                    invoice.item_add_classcard(ccdID)

            # Check for subscription
            if row.school_subscriptions_id:
                ## Deliver subscription
                # Determine payment method
                cs_payment_method = get_sys_property(
                    'shop_subscriptions_payment_method')
                if cs_payment_method == 'mollie':
                    payment_method_id = 100
                else:
                    payment_method_id = 3

                subscription_start = TODAY_LOCAL
                ssu = SchoolSubscription(row.school_subscriptions_id)
                csID = ssu.sell_to_customer(
                    self.order.auth_customer_id,
                    subscription_start,
                    payment_methods_id=payment_method_id)

                # Add credits for the first month
                cs = CustomerSubscription(csID)
                cs.add_credits_month(subscription_start.year,
                                     subscription_start.month)

                # clear cache
                ocm.clear_customers_subscriptions(self.order.auth_customer_id)

                if create_invoice:
                    # This will also add the registration fee if required.
                    iiID = invoice.item_add_subscription(
                        csID, TODAY_LOCAL.year, TODAY_LOCAL.month)

            # Check for membership
            if row.school_memberships_id:
                # Deliver membership
                membership_start = TODAY_LOCAL
                sme = SchoolMembership(row.school_memberships_id)
                cmID = sme.sell_to_customer(
                    self.order.auth_customer_id,
                    membership_start,
                    invoice=False,  # Don't create a separate invoice
                )

                # clear cache
                ocm.clear_customers_memberships(self.order.auth_customer_id)

                if create_invoice:
                    cm = CustomerMembership(cmID)

                    # Check if price exists and > 0:
                    if sme.row.Price:
                        iiID = invoice.item_add_membership(cmID)

            # Check for workshop
            if row.workshops_products_id:
                # Deliver workshop product
                wsp = WorkshopProduct(row.workshops_products_id)
                wspcID = wsp.sell_to_customer(self.order.auth_customer_id,
                                              invoice=False)

                # Add workshop product to invoice
                if create_invoice:
                    invoice.item_add_workshop_product(wspcID)

                # Check if sold out
                if wsp.is_sold_out():
                    # Cancel all unpaid orders with a sold out product for this workshop
                    ws = Workshop(wsp.wsID)
                    ws.cancel_orders_with_sold_out_products()

            # Check for classes
            if row.classes_id:
                # Deliver class
                ah = AttendanceHelper()
                if row.AttendanceType == 1:
                    result = ah.attendance_sign_in_trialclass(
                        self.order.auth_customer_id,
                        row.classes_id,
                        row.ClassDate,
                        online_booking=class_online_booking,
                        invoice=False,
                        booking_status=class_booking_status)
                elif row.AttendanceType == 2:
                    result = ah.attendance_sign_in_dropin(
                        self.order.auth_customer_id,
                        row.classes_id,
                        row.ClassDate,
                        online_booking=class_online_booking,
                        invoice=False,
                        booking_status=class_booking_status,
                    )

                if create_invoice:
                    invoice.item_add_class_from_order(row, result['caID'])

                # Clear api cache to update available spaces
                cache_clear_classschedule_api()

            # Check for donation
            if row.Donation:
                # Add donation line to invoice
                if create_invoice and create_invoice_for_donations:
                    invoice.item_add_donation(row.TotalPriceVAT,
                                              row.Description)

            # Check for custom item
            if row.Custom:
                # Add custom line to invoice
                if create_invoice:
                    invoice.item_add_custom_from_order(row)

        # Notify customer of new invoice
        #if create_invoice:
        #invoice.mail_customer_invoice_created()

        # Update status
        self.set_status_delivered()
        # Notify customer of order delivery
        self._deliver_mail_customer()

        return dict(iID=iID, invoice=invoice)
    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
Esempio n. 13
0
    def deliver(self):
        """
            Create invoice for order and deliver goods
        """
        from os_attendance_helper import AttendanceHelper
        from os_invoice import Invoice
        from os_school_classcard import SchoolClasscard
        from os_school_subscription import SchoolSubscription
        from os_workshop import Workshop
        from os_workshop_product import WorkshopProduct

        cache_clear_classschedule_api = current.globalenv['cache_clear_classschedule_api']
        get_sys_property = current.globalenv['get_sys_property']
        db = current.db
        T = current.T

        create_invoice = False
        iID = None
        invoice = None
        # Only create an invoice if order amount > 0
        amounts = self.get_amounts()

        sys_property_create_invoice = 'shop_donations_create_invoice'
        create_invoice_for_donations = get_sys_property(sys_property_create_invoice)
        if create_invoice_for_donations == 'on':
            create_invoice_for_donations = True
        else:
            create_invoice_for_donations = False

        if amounts:
            if amounts.TotalPriceVAT > 0:
                if not self.order.Donation or (self.order.Donation and create_invoice_for_donations):
                    create_invoice = True

                    # Create blank invoice
                    igpt = db.invoices_groups_product_types(ProductType='shop')

                    iID = db.invoices.insert(
                        invoices_groups_id=igpt.invoices_groups_id,
                        Description=T('Order #') + unicode(self.coID),
                        Status='sent'
                    )

                    # Link invoice to order
                    db.invoices_customers_orders.insert(
                        customers_orders_id = self.coID,
                        invoices_id = iID
                    )

                    # Call init function for invoices to set Invoice # , etc.
                    invoice = Invoice(iID)
                    invoice.link_to_customer(self.order.auth_customer_id)

        # Add items to the invoice
        rows = self.get_order_items_rows()

        for row in rows:
            ##
            # Only rows where school_classcards_id, workshops_products_id , classes_id or Donation are set
            # are put on the invoice
            ##

            # Check for classcard
            if row.school_classcards_id:
                # Deliver card
                card_start = datetime.date.today()
                scd = SchoolClasscard(row.school_classcards_id)
                ccdID = scd.sell_to_customer(self.order.auth_customer_id,
                                             card_start,
                                             invoice=False)
                # Add card to invoice
                if create_invoice:
                    invoice.item_add_classcard(ccdID)

            # Check for workshop
            if row.workshops_products_id:
                # Deliver workshop product
                wsp = WorkshopProduct(row.workshops_products_id)
                wspcID = wsp.sell_to_customer(self.order.auth_customer_id,
                                              invoice=False)

                # Add workshop product to invoice
                if create_invoice:
                    invoice.item_add_workshop_product(wspcID)

                # Check if sold out
                if wsp.is_sold_out():
                    # Cancel all unpaid orders with a sold out product for this workshop
                    ws = Workshop(wsp.wsID)
                    ws.cancel_orders_with_sold_out_products()

            # Check for classes
            if row.classes_id:
                # Deliver class
                ah = AttendanceHelper()
                if row.AttendanceType == 1:
                    result = ah.attendance_sign_in_trialclass(self.order.auth_customer_id,
                                                              row.classes_id,
                                                              row.ClassDate,
                                                              online_booking=True,
                                                              invoice=False)
                elif row.AttendanceType == 2:
                    result = ah.attendance_sign_in_dropin(self.order.auth_customer_id,
                                                          row.classes_id,
                                                          row.ClassDate,
                                                          online_booking=True,
                                                          invoice=False)

                if create_invoice:
                    invoice.item_add_class_from_order(row, result['caID'])

                # Clear api cache to update available spaces
                cache_clear_classschedule_api()

            # Check for donation
            if row.Donation:
                # Add donation line to invoice
                if create_invoice and create_invoice_for_donations:
                    invoice.item_add_donation(row.TotalPriceVAT, row.Description)


        # Notify customer of new invoice
        #if create_invoice:
            #invoice.mail_customer_invoice_created()

        # Update status
        self.set_status_delivered()
        # Notify customer of order delivery
        self._deliver_mail_customer()

        return dict(iID=iID, invoice=invoice)
    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