Пример #1
0
    def order_item_add_subscription(self, school_subscriptions_id, startdate):
        """
            :param school_subscriptions_id: db.school_subscriptions.id
            :return : db.customers_orders_items.id of inserted item
        """
        from os_school_subscription import SchoolSubscription

        db = current.db
        T = current.T

        ssu = SchoolSubscription(school_subscriptions_id)
        ssu_tax_rates = ssu.get_tax_rates_on_date(startdate)

        coiID = db.customers_orders_items.insert(
            customers_orders_id=self.coID,
            school_subscriptions_id=school_subscriptions_id,
            ProductName=T('Subscription'),
            Description=ssu.get_name(),
            Quantity=1,
            Price=ssu.get_price_on_date(startdate, formatted=False),
            tax_rates_id=ssu_tax_rates.tax_rates.id,
            accounting_glaccounts_id=ssu.row.accounting_glaccounts_id,
            accounting_costcenters_id=ssu.row.accounting_costcenters_id,
        )

        self.set_amounts()

        return coiID
    def set_min_enddate(self):
        """
        Set MinEnddate
        :return: None
        """
        from os_school_subscription import SchoolSubscription

        ssu = SchoolSubscription(self.ssuID)
        self.cs.MinEnddate = ssu._sell_to_customer_get_min_end_date(self.startdate)

        self.cs.update_record()
Пример #3
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)
Пример #4
0
    def item_add_subscription(self,
                              SubscriptionYear,
                              SubscriptionMonth,
                              description=''):
        """
            :param SubscriptionYear: Year of subscription
            :param SubscriptionMonth: Month of subscription
            :return: db.invoices_items.id
        """
        from general_helpers import get_last_day_month

        from os_customer_subscription import CustomerSubscription
        from os_school_subscription import SchoolSubscription

        db = current.db
        DATE_FORMAT = current.DATE_FORMAT

        next_sort_nr = self.get_item_next_sort_nr()

        date = datetime.date(int(SubscriptionYear), int(SubscriptionMonth), 1)

        ics = db.invoices_customers_subscriptions(invoices_id=self.invoices_id)
        csID = ics.customers_subscriptions_id
        cs = CustomerSubscription(csID)
        ssuID = cs.ssuID
        ssu = SchoolSubscription(ssuID)
        row = ssu.get_tax_rates_on_date(date)

        if row:
            tax_rates_id = row.school_subscriptions_price.tax_rates_id
        else:
            tax_rates_id = None

        period_start = date
        period_end = get_last_day_month(date)
        glaccount = ssu.get_glaccount_on_date(date)
        costcenter = ssu.get_costcenter_on_date(date)
        price = 0

        # check for alt price
        csap = db.customers_subscriptions_alt_prices
        query = (csap.customers_subscriptions_id == csID) & \
                (csap.SubscriptionYear == SubscriptionYear) & \
                (csap.SubscriptionMonth == SubscriptionMonth)
        csap_rows = db(query).select(csap.ALL)
        if csap_rows:
            csap_row = csap_rows.first()
            price = csap_row.Amount
            description = csap_row.Description
        else:
            price = ssu.get_price_on_date(date, False)

            broken_period = False
            if cs.startdate > date and cs.startdate <= period_end:
                # Start later in month
                broken_period = True
                period_start = cs.startdate
                delta = period_end - cs.startdate
                cs_days = delta.days + 1
                total_days = period_end.day

            if cs.enddate:
                if cs.enddate >= date and cs.enddate < period_end:
                    # End somewhere in month
                    broken_period = True

                    delta = cs.enddate - date
                    cs_days = delta.days + 1
                    total_days = period_end.day

                    period_end = cs.enddate

            if broken_period:
                price = round(
                    float(cs_days) / float(total_days) * float(price), 2)

            if not description:
                description = cs.name.decode(
                    'utf-8') + u' ' + period_start.strftime(
                        DATE_FORMAT) + u' - ' + period_end.strftime(
                            DATE_FORMAT)

        iiID = db.invoices_items.insert(invoices_id=self.invoices_id,
                                        ProductName=current.T("Subscription") +
                                        ' ' + unicode(csID),
                                        Description=description,
                                        Quantity=1,
                                        Price=price,
                                        Sorting=next_sort_nr,
                                        tax_rates_id=tax_rates_id,
                                        accounting_glaccounts_id=glaccount,
                                        accounting_costcenters_id=costcenter)

        ##
        # Check if a registration fee should be added
        ##
        query = (
            ((db.customers_subscriptions.auth_customer_id
              == cs.auth_customer_id) &
             (db.customers_subscriptions.id != cs.csID) &
             (db.customers_subscriptions.school_subscriptions_id == cs.ssuID))
            | (db.customers_subscriptions.RegistrationFeePaid == True))

        fee_paid_in_past = db(query).count()
        ssu = db.school_subscriptions(ssuID)
        if not fee_paid_in_past and ssu.RegistrationFee:  # Registration fee not already paid and RegistrationFee defined?
            regfee_to_be_paid = ssu.RegistrationFee or 0
            if regfee_to_be_paid:
                db.invoices_items.insert(
                    invoices_id=self.invoices_id,
                    ProductName=current.T("Registration fee"),
                    Description=current.T('One time registration fee'),
                    Quantity=1,
                    Price=regfee_to_be_paid,
                    Sorting=next_sort_nr,
                    tax_rates_id=tax_rates_id,
                )

                # Mark registration fee as paid for subscription
                db.customers_subscriptions[cs.csID] = dict(
                    RegistrationFeePaid=True)

        ##
        # Always call these
        ##
        # This calls self.on_update()
        self.set_amounts()

        return iiID
Пример #5
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)
Пример #6
0
    def item_add_subscription(self, csID, SubscriptionYear, SubscriptionMonth, description=''):
        """
            :param SubscriptionYear: Year of subscription
            :param SubscriptionMonth: Month of subscription
            :return: db.invoices_items.id
        """
        T = current.T

        from general_helpers import get_last_day_month

        from os_customer_subscription import CustomerSubscription
        from os_school_subscription import SchoolSubscription

        db = current.db
        DATE_FORMAT = current.DATE_FORMAT

        next_sort_nr = self.get_item_next_sort_nr()

        date = datetime.date(int(SubscriptionYear),
                             int(SubscriptionMonth),
                             1)


        cs = CustomerSubscription(csID)
        ssuID = cs.ssuID
        ssu = SchoolSubscription(ssuID)
        row = ssu.get_tax_rates_on_date(date)
        if row:
            tax_rates_id = row.school_subscriptions_price.tax_rates_id
        else:
            tax_rates_id = None

        period_start = date
        first_day_month = date
        last_day_month = get_last_day_month(date)
        period_end = last_day_month
        glaccount = ssu.get_glaccount_on_date(date)
        costcenter = ssu.get_costcenter_on_date(date)
        price = 0

        # check for alt price
        csap = db.customers_subscriptions_alt_prices
        query = (csap.customers_subscriptions_id == csID) & \
                (csap.SubscriptionYear == SubscriptionYear) & \
                (csap.SubscriptionMonth == SubscriptionMonth)
        csap_rows = db(query).select(csap.ALL)
        if csap_rows:
            # alt. price overrides broken period
            csap_row = csap_rows.first()
            price    = csap_row.Amount
            description = csap_row.Description
        else:
            price = ssu.get_price_on_date(date, False)

            broken_period = False
            pause = False

            # Check pause
            query = (db.customers_subscriptions_paused.customers_subscriptions_id == csID) & \
                    (db.customers_subscriptions_paused.Startdate <= last_day_month) & \
                    ((db.customers_subscriptions_paused.Enddate >= first_day_month) |
                     (db.customers_subscriptions_paused.Enddate == None))
            rows = db(query).select(db.customers_subscriptions_paused.ALL)
            if rows:
                pause = rows.first()

            # Calculate days to be paid
            if cs.startdate > first_day_month and cs.startdate <= last_day_month:
                # Start later in month
                broken_period = True
                period_start = cs.startdate


            if cs.enddate:
                if cs.enddate >= first_day_month and cs.enddate < last_day_month:
                    # End somewhere in month
                    broken_period = True
                    period_end = cs.enddate


            Range = namedtuple('Range', ['start', 'end'])
            period_range = Range(start=period_start, end=period_end)
            period_days = (period_range.end - period_range.start).days + 1

            if pause:
                pause_range = Range(start=pause.Startdate, end=pause.Enddate)
                latest_start = max(period_range.start, pause_range.start)
                earliest_end = min(pause_range.end, pause_range.end)
                delta = (earliest_end - latest_start).days + 1
                overlap = max(0, delta)

                # Subtract pause overlap from period to be paid
                period_days = period_days - overlap

            month_days = (last_day_month - first_day_month).days + 1

            price = round(((float(period_days) / float(month_days)) * float(price)), 2)

            if not description:
                description = cs.name.decode('utf-8') + u' ' + period_start.strftime(DATE_FORMAT) + u' - ' + period_end.strftime(DATE_FORMAT)
                if pause:
                    description += u'\n'
                    description += u"(" + T("Pause") + u": "
                    description += pause.Startdate.strftime(DATE_FORMAT) + u" - "
                    description += pause.Enddate.strftime(DATE_FORMAT) + u" | "
                    description += T("Days paid this period: ")
                    description += unicode(period_days)
                    description += u")"

        iiID = db.invoices_items.insert(
            invoices_id = self.invoices_id,
            ProductName = current.T("Subscription") + ' ' + unicode(csID),
            Description = description,
            Quantity = 1,
            Price = price,
            Sorting = next_sort_nr,
            tax_rates_id = tax_rates_id,
            accounting_glaccounts_id = glaccount,
            accounting_costcenters_id = costcenter

        )

        ##
        # Check if a registration fee should be added
        ##
        query = (((db.customers_subscriptions.auth_customer_id == cs.auth_customer_id) &
                 (db.customers_subscriptions.id != cs.csID) &
                 (db.customers_subscriptions.school_subscriptions_id == cs.ssuID)) |
                 (db.customers_subscriptions.RegistrationFeePaid == True))

        fee_paid_in_past = db(query).count()
        ssu = db.school_subscriptions(ssuID)
        if not fee_paid_in_past and ssu.RegistrationFee: # Registration fee not already paid and RegistrationFee defined?
            regfee_to_be_paid = ssu.RegistrationFee or 0
            if regfee_to_be_paid:
                db.invoices_items.insert(
                    invoices_id = self.invoices_id,
                    ProductName = current.T("Registration fee"),
                    Description = current.T('One time registration fee'),
                    Quantity = 1,
                    Price = regfee_to_be_paid,
                    Sorting = next_sort_nr,
                    tax_rates_id = tax_rates_id,
                )

                # Mark registration fee as paid for subscription
                db.customers_subscriptions[cs.csID] = dict(RegistrationFeePaid=True)

        ##
        # Always call these
        ##
        # Link invoice item to subscription
        self.link_item_to_customer_subscription(csID, iiID)
        # This calls self.on_update()
        self.set_amounts()

        return iiID
    def create_invoice_for_month(self, SubscriptionYear, SubscriptionMonth, 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