Exemplo n.º 1
0
def test_update_booking_custom_cost():
    info = usagelib.usage_resource.info(booking_id)
    old_total = info.total
    new_cost = old_total + 100
    usagelib.usage_resource.update(booking_id, cost=new_cost)
    usage = usagelib.usage_resource.info(booking_id)
    new_total = usage.total
    env.context.pgcursor.connection.commit()
    taxes = costlib.to_decimal(usage.tax_dict['total'])
    taxes_included = invoicepreflib.invoicepref_resource.info(test_data.bizplace_id).tax_included
    expected_total = new_cost if taxes_included else (new_cost + taxes)
    assert new_total != old_total
    assert new_total == expected_total
Exemplo n.º 2
0
def apply_taxes(resource_id, resource_owner, cost):
    cost = float(cost)
    tax_info = resource_lib.resource_resource.get_taxinfo(resource_id, resource_owner)
    tax_included = tax_info['tax_included']
    taxes = tax_info['taxes'] if tax_info['taxes'] else {}
    tax_names = taxes.keys()
    total_tax_level = sum(map(float, taxes.values()))
    if tax_included:
        basic_cost = cost / ((100 + total_tax_level)/100.0)
        breakdown = tuple((name, level, (basic_cost * float(float(level)/100.0))) for (name, level) in taxes.items())
        total = cost
        total_tax = sum(item[2] for item in breakdown)
    else:
        total_tax = float(cost) * (total_tax_level/100.0)
        breakdown = tuple((name, level, (cost * float(float(level)/100.0))) for (name, level) in taxes.items())
        total = cost + total_tax

    return costlib.to_decimal(total), dict(total=total_tax, breakdown=breakdown)
Exemplo n.º 3
0
def calculate_cost(member_id, resource_id, resource_owner, quantity, starts, ends=None, cost=None, return_taxes=False):
    """
    returns {calculate_cost: amount(decimal), taxes: ((Tax1, 10.00, 39.00), (Tax2,..), ..)}
    """
    starts = commonlib.helpers.iso2datetime(starts)
    ends = commonlib.helpers.iso2datetime(ends) if ends else starts
    usage = odict(member_id=member_id, resource_id=resource_id, resource_owner=resource_owner, quantity=quantity, starts=starts, ends=ends, cost=cost)
    processor = costlib.Processor(usage, rules)
    calculated_cost = processor.run()
    cost = cost if cost else calculated_cost
    result = dict(calculated_cost=costlib.to_decimal(calculated_cost))
    if return_taxes:
        exemptions_at = invoicepref_store.get_by({'owner':member_id}, fields=['tax_exemptions_at'])[0].tax_exemptions_at or []
        exemption_applicable = resource_owner in exemptions_at
        if exemption_applicable:
            total = cost
            taxes = dict(total=0, breakdown=())
        else:
            total, taxes = apply_taxes(resource_id, resource_owner, cost)
        result['taxes'] = taxes
        result['total'] = total
    return result
Exemplo n.º 4
0
    def new(self, resource_id, resource_name, resource_owner, member, start_time, end_time=None, quantity=1, cost=None, tax_dict={}, invoice=None, cancelled_against=None, calculated_cost=None, notes=None, usages=[], name=None, description=None, no_of_people=0, suppress_notification=False, public=False, repetition_id=None):
        # TODO shouldn't we name the parameter member_id and not member

        if quantity is None: quantity = 1
        if not end_time: end_time = start_time

        resource = resourcelib.resource_resource.info(resource_id) if resource_id else None
        member_dict = member_store.get(member, ['id', 'first_name', 'name', 'email'])
        if resource:
            resource_owner = resource.owner
            if not resource.enabled or resource.archived:
                raise be.errors.ErrorWithHint('Resource is either not enabled or is archived')

        if end_time < start_time:
            raise be.errors.ErrorWithHint('Start time is less than end time')
        created = datetime.datetime.now()

        if cancelled_against:
            total = cost + costlib.to_decimal(tax_dict.get('total', 0))
        else:
            result = pricinglib.calculate_cost(member_id=member, resource_id=resource_id, resource_owner=resource_owner, quantity=quantity, starts=start_time, ends=end_time, cost=cost, return_taxes=True)
            calculated_cost = result['calculated_cost']
            total = result['total']
            tax_dict = result['taxes']
            if cost is None:
                cost = calculated_cost

        pricing = pricinglib.pricings.get(member, resource_id, start_time) if resource_id else None
        data = dict(resource_id=resource_id, resource_name=resource_name, resource_owner=resource_owner, quantity=quantity, calculated_cost=calculated_cost, cost=cost, total=total, tax_dict=tax_dict, invoice=invoice, start_time=start_time, end_time=end_time, member=member, created_by=env.context.user_id, created=created, cancelled_against=cancelled_against, pricing=pricing, notes=notes, name=name, description=description, no_of_people=no_of_people, public=public, repetition_id=repetition_id)
        if resource and (resource.calc_mode == resourcelib.CalcMode.quantity_based):
            data['end_time'] == start_time
        else:
            data['quantity'] == 1

        if not cancelled_against and not resource_id == 0:
            usages_dict = dict((usage['resource_id'], usage) for usage in usages)
            relations = resourcelib.resource_resource.get_relations(resource_id)
            contained_usages_data = []
            suggested_usages_data = []

            for res in relations[True]:
                usage = usages_dict.get(res.id, {})
                new_data = dict(resource_id=res.id,
                    resource_name=res.name,
                    resource_owner=resource_owner,
                    member=member,
                    suppress_notification=True,
                    start_time=start_time,
                    end_time=start_time if res.calc_mode == resourcelib.CalcMode.quantity_based else data['end_time'],
                    quantity=usage.get('quantity', 1))
                contained_usages_data.append(new_data)

            contained_usage_ids = [self.new(**new_data) for new_data in contained_usages_data]
            suggested_usage_ids = add_suggested_usages(resource['owner_id'], data, relations[False], usages)

            also_booked_text = ', '.join(res.name for res in relations[False] if res.id in usages_dict)

            data['usages_contained'] = contained_usage_ids
            data['usages_suggested'] = suggested_usage_ids

        usage_id = usage_store.add(**data)


        if resource and resource.calc_mode == resourcelib.CalcMode.time_based:
            reserve_slots(usage_id, resource.id, start_time, end_time)

        suppress_email = cancelled_against or suppress_notification or resource_id == 0 or \
            (resource and resource.calc_mode != resourcelib.CalcMode.time_based)
        if not suppress_email:
            owner = bizplace_store.get(resource_owner, ['id', 'name', 'booking_email', 'currency', 'host_email', 'phone'])

            also_booked_text = 'Also booked: ' + also_booked_text if also_booked_text else ''
            email_data = dict(LOCATION=owner.name, MEMBER_EMAIL=member_dict.email, BOOKING_CONTACT=owner.booking_email or owner.host_email, MEMBER_FIRST_NAME=member_dict.first_name, RESOURCE=resource_name, BOOKING_START=commonlib.helpers.time4human(start_time), BOOKING_END=commonlib.helpers.time4human(end_time), BOOKING_DATE=commonlib.helpers.date4human(start_time), CURRENCY=owner.currency, COST=cost, HOSTS_EMAIL=owner.host_email, LOCATION_PHONE=owner.phone)
            mailtext = messagecustlib.get(owner.id, 'booking_confirmation')
            notification = commonlib.messaging.messages.booking_confirmation(email_data, overrides=dict(plain=mailtext, bcc='*****@*****.**'))
            notification.build()
            notification.email()

        a_data = dict(resource_id=resource_id, resource_name=resource_name, resource_owner=resource_owner, member_id=member_dict.id, member_name=member_dict.name, start_time=start_time, end_time=end_time, actor_id=env.context.user_id, actor_name=env.context.name, created=created)
        activity_id = activitylib.add('booking', 'booking_created', a_data, created)

        return usage_id