Example #1
0
def user_expense_perm(user):
    """compute user perm and returns expense_administrator, expense_subsidiary_manager, expense_manager, expense_paymaster, expense_requester"""
    expense_administrator = user.is_superuser or user_has_feature(
        user, "expense_administrator")
    expense_subsidiary_manager = expense_administrator or user_has_feature(
        user, "expense_subsidiary_manager")
    expense_manager = expense_administrator or user_has_feature(
        user, "expense_manager")
    expense_paymaster = expense_administrator or user_has_feature(
        user, "expense_paymaster")
    expense_requester = expense_administrator or user_has_feature(
        user, "expense")

    return expense_administrator, expense_subsidiary_manager, expense_manager, expense_paymaster, expense_requester
Example #2
0
 def __getitem__(self, feature):
     return user_has_feature(self.user, str(feature))
Example #3
0
def bill_review(request):
    """Review of bills: bills overdue, due soon, or to be created"""
    today = date.today()
    wait_warning = timedelta(
        15)  # wait in days used to warn that a bill is due soon

    subsidiary = get_subsidiary_from_session(request)

    # Get bills overdue, due soon, litigious and recently paid
    overdue_bills = ClientBill.objects.filter(
        state="1_SENT", due_date__lte=today).select_related()
    soondue_bills = ClientBill.objects.filter(
        state="1_SENT",
        due_date__gt=today,
        due_date__lte=(today + wait_warning)).select_related()
    recent_bills = ClientBill.objects.filter(
        state="2_PAID").order_by("-payment_date").select_related()
    litigious_bills = ClientBill.objects.filter(
        state="3_LITIGIOUS").select_related()
    supplier_overdue_bills = SupplierBill.objects.filter(
        state__in=("1_RECEIVED", "1_VALIDATED"),
        due_date__lte=today).select_related()
    supplier_soondue_bills = SupplierBill.objects.filter(
        state__in=("1_RECEIVED", "1_VALIDATED"),
        due_date__gt=today).select_related()

    # Filter bills on subsidiary if defined
    if subsidiary:
        overdue_bills = overdue_bills.filter(lead__subsidiary=subsidiary)
        soondue_bills = soondue_bills.filter(lead__subsidiary=subsidiary)
        recent_bills = recent_bills.filter(lead__subsidiary=subsidiary)
        litigious_bills = litigious_bills.filter(lead__subsidiary=subsidiary)
        supplier_overdue_bills = supplier_overdue_bills.filter(
            lead__subsidiary=subsidiary)
        supplier_soondue_bills = supplier_soondue_bills.filter(
            lead__subsidiary=subsidiary)

    # Limit recent bill to last 20 ones
    recent_bills = recent_bills[:20]

    # Compute totals
    soondue_bills_total = soondue_bills.aggregate(Sum("amount"))["amount__sum"]
    overdue_bills_total = overdue_bills.aggregate(Sum("amount"))["amount__sum"]
    litigious_bills_total = litigious_bills.aggregate(
        Sum("amount"))["amount__sum"]
    soondue_bills_total_with_vat = sum([
        bill.amount_with_vat for bill in soondue_bills if bill.amount_with_vat
    ])
    overdue_bills_total_with_vat = sum([
        bill.amount_with_vat for bill in overdue_bills if bill.amount_with_vat
    ])
    litigious_bills_total_with_vat = sum([
        bill.amount_with_vat for bill in litigious_bills
        if bill.amount_with_vat
    ])

    # Get leads with done timesheet in past three month that don't have bill yet
    leads_without_bill = Lead.objects.filter(
        state="WON",
        mission__timesheet__working_date__gte=(date.today() - timedelta(90)))
    leads_without_bill = leads_without_bill.annotate(
        Count("clientbill")).filter(clientbill__count=0)
    if subsidiary:
        leads_without_bill = leads_without_bill.filter(subsidiary=subsidiary)

    return render(
        request, "billing/bill_review.html", {
            "overdue_bills":
            overdue_bills,
            "soondue_bills":
            soondue_bills,
            "recent_bills":
            recent_bills,
            "litigious_bills":
            litigious_bills,
            "soondue_bills_total":
            soondue_bills_total,
            "overdue_bills_total":
            overdue_bills_total,
            "litigious_bills_total":
            litigious_bills_total,
            "soondue_bills_total_with_vat":
            soondue_bills_total_with_vat,
            "overdue_bills_total_with_vat":
            overdue_bills_total_with_vat,
            "litigious_bills_total_with_vat":
            litigious_bills_total_with_vat,
            "leads_without_bill":
            leads_without_bill,
            "supplier_soondue_bills":
            supplier_soondue_bills,
            "supplier_overdue_bills":
            supplier_overdue_bills,
            "billing_management":
            user_has_feature(request.user, "billing_management"),
            "consultant":
            Consultant.objects.filter(
                trigramme__iexact=request.user.username).first(),
            "user":
            request.user
        })
Example #4
0
def client_bill(request, bill_id=None):
    """Add or edit client bill"""
    billDetailFormSet = None
    billExpenseFormSet = None
    billing_management_feature = "billing_management"
    forbiden = HttpResponseRedirect(reverse("core:forbiden"))
    if bill_id:
        try:
            bill = ClientBill.objects.get(id=bill_id)
        except ClientBill.DoesNotExist:
            raise Http404
    else:
        bill = None
    BillDetailFormSet = inlineformset_factory(ClientBill,
                                              BillDetail,
                                              formset=BillDetailInlineFormset,
                                              form=BillDetailForm,
                                              fields="__all__")
    BillExpenseFormSet = inlineformset_factory(
        ClientBill,
        BillExpense,
        formset=BillExpenseInlineFormset,
        form=BillExpenseForm,
        fields="__all__")
    wip_status = ("0_DRAFT", "0_PROPOSED")
    if request.POST:
        form = ClientBillForm(request.POST, request.FILES, instance=bill)
        # First, ensure user is allowed to manipulate the bill
        if bill and bill.state not in wip_status and not user_has_feature(
                request.user, billing_management_feature):
            return forbiden
        if form.data["state"] not in wip_status and not user_has_feature(
                request.user, billing_management_feature):
            return forbiden
        # Now, process form
        if bill and bill.state in wip_status:
            billDetailFormSet = BillDetailFormSet(request.POST, instance=bill)
            billExpenseFormSet = BillExpenseFormSet(request.POST,
                                                    instance=bill)
        if form.is_valid() and (billDetailFormSet is None
                                or billDetailFormSet.is_valid()) and (
                                    billExpenseFormSet is None
                                    or billExpenseFormSet.is_valid()):
            bill = form.save()
            if billDetailFormSet:
                billDetailFormSet.save()
            if billExpenseFormSet:
                billExpenseFormSet.save()
            bill.save()  # Again, to take into account modified details.
            if bill.state in wip_status:
                success_url = reverse_lazy("billing:client_bill",
                                           args=[
                                               bill.id,
                                           ])
            else:
                success_url = request.GET.get(
                    'return_to', False) or reverse_lazy(
                        "crm:company_detail",
                        args=[
                            bill.lead.client.organisation.company.id,
                        ]) + "#goto_tab-billing"
                if bill.bill_file:
                    if form.changed_data == [
                            "state"
                    ] and billDetailFormSet is None and billExpenseFormSet is None:
                        # only state has change. No need to regenerate bill file.
                        messages.add_message(request, messages.INFO,
                                             _("Bill state has beed updated"))
                    elif "bill_file" in form.changed_data:
                        # a file has been provided by user himself. We must not generate a file and overwrite it.
                        messages.add_message(
                            request, messages.WARNING,
                            _("Using custom user file to replace current bill")
                        )
                    else:
                        # bill file exist but authorized admin change information and do not provide custom file. Let's generate again bill file
                        messages.add_message(
                            request, messages.WARNING,
                            _("A new bill is generated and replace the previous one"
                              ))
                        if os.path.exists(bill.bill_file.path):
                            os.remove(bill.bill_file.path)
                        generate_bill_pdf(bill, request)
                else:
                    # Bill file still not exist. Let's create it
                    messages.add_message(
                        request, messages.INFO,
                        _("A new bill file has been generated"))
                    generate_bill_pdf(bill, request)
            return HttpResponseRedirect(success_url)
    else:
        if bill:
            # Create a form to edit the given bill
            form = ClientBillForm(instance=bill)
            if bill.state in wip_status:
                billDetailFormSet = BillDetailFormSet(instance=bill)
                billExpenseFormSet = BillExpenseFormSet(instance=bill)
        else:
            # Still no bill, let's create it with its detail if at least mission or lead has been provided
            missions = []
            if request.GET.get("lead"):
                lead = Lead.objects.get(id=request.GET.get("lead"))
                missions = lead.mission_set.all()  # take all missions
            if request.GET.get("mission"):
                missions = [Mission.objects.get(id=request.GET.get("mission"))]
            if missions:
                bill = ClientBill.objects.create(lead=missions[0].lead)
                bill.save()
            for mission in missions:
                if mission.billing_mode == "TIME_SPENT":
                    if request.GET.get("start_date") and request.GET.get(
                            "end_date"):
                        start_date = date(
                            int(request.GET.get("start_date")[0:4]),
                            int(request.GET.get("start_date")[4:6]), 1)
                        end_date = date(int(request.GET.get("end_date")[0:4]),
                                        int(request.GET.get("end_date")[4:6]),
                                        1)
                    else:
                        start_date = previousMonth(previousMonth(date.today()))
                        end_date = previousMonth(date.today())
                    update_client_bill_from_timesheet(bill, mission,
                                                      start_date, end_date)
                else:  # FIXED_PRICE mission
                    proportion = request.GET.get("proportion", 0.30)
                    bill = update_client_bill_from_proportion(
                        bill, mission, proportion=proportion)

            if bill:
                form = ClientBillForm(instance=bill)
                billDetailFormSet = BillDetailFormSet(instance=bill)
                billExpenseFormSet = BillExpenseFormSet(instance=bill)
            else:
                # Simple virgin new form
                form = ClientBillForm()
    return render(
        request, "billing/client_bill_form.html", {
            "bill_form": form,
            "detail_formset": billDetailFormSet,
            "detail_formset_helper": BillDetailFormSetHelper(),
            "expense_formset": billExpenseFormSet,
            "expense_formset_helper": BillExpenseFormSetHelper(),
            "bill_id": bill.id if bill else None,
            "can_delete": bill.state in wip_status if bill else False,
            "can_preview": bill.state in wip_status if bill else False,
            "user": request.user
        })
Example #5
0
def client_bill(request, bill_id=None):
    """Add or edit client bill"""
    billDetailFormSet = None
    billExpenseFormSet = None
    billing_management_feature = "billing_management"
    forbiden = HttpResponseRedirect(reverse("core:forbiden"))
    if bill_id:
        try:
            bill = ClientBill.objects.get(id=bill_id)
        except ClientBill.DoesNotExist:
            raise Http404
    else:
        bill = None
    BillDetailFormSet = inlineformset_factory(ClientBill,
                                              BillDetail,
                                              formset=BillDetailInlineFormset,
                                              form=BillDetailForm,
                                              fields="__all__")
    BillExpenseFormSet = inlineformset_factory(
        ClientBill,
        BillExpense,
        formset=BillExpenseInlineFormset,
        form=BillExpenseForm,
        fields="__all__")
    wip_status = ("0_DRAFT", "0_PROPOSED")
    if request.POST:
        form = ClientBillForm(request.POST, request.FILES, instance=bill)
        # First, ensure user is allowed to manipulate the bill
        if bill and bill.state not in wip_status and not user_has_feature(
                request.user, billing_management_feature):
            return forbiden
        if form.data["state"] not in wip_status and not user_has_feature(
                request.user, billing_management_feature):
            return forbiden
        # Now, process form
        if bill and bill.state in wip_status:
            billDetailFormSet = BillDetailFormSet(request.POST, instance=bill)
            billExpenseFormSet = BillExpenseFormSet(request.POST,
                                                    instance=bill)
        if form.is_valid() and (billDetailFormSet is None
                                or billDetailFormSet.is_valid()) and (
                                    billExpenseFormSet is None
                                    or billExpenseFormSet.is_valid()):
            bill = form.save()
            if billDetailFormSet:
                billDetailFormSet.save()
            if billExpenseFormSet:
                billExpenseFormSet.save()
            bill.save()  # Again, to take into account modified details.
            if bill.state in wip_status:
                success_url = reverse_lazy("billing:client_bill",
                                           args=[
                                               bill.id,
                                           ])
            else:
                success_url = request.GET.get(
                    'return_to', False) or reverse_lazy(
                        "crm:company_detail",
                        args=[
                            bill.lead.client.organisation.company.id,
                        ]) + "#goto_tab-billing"
                if not bill.bill_file:
                    fake_http_request = request
                    fake_http_request.method = "GET"
                    response = BillPdf.as_view()(fake_http_request,
                                                 bill_id=bill.id)
                    pdf = response.rendered_content.read()
                    filename = bill_pdf_filename(bill)
                    content = ContentFile(pdf, name=filename)
                    bill.bill_file.save(filename, content)
                    bill.save()
            return HttpResponseRedirect(success_url)
    else:
        if bill:
            form = ClientBillForm(instance=bill)
            if bill.state in wip_status:
                billDetailFormSet = BillDetailFormSet(instance=bill)
                billExpenseFormSet = BillExpenseFormSet(instance=bill)
        else:
            # Still no bill, let's create it with its detail if at least mission has been provided
            if request.GET.get("mission"):
                mission = Mission.objects.get(id=request.GET.get("mission"))
                if mission.billing_mode == "TIME_SPENT":
                    if request.GET.get("month") and request.GET.get("year"):
                        month = date(int(request.GET.get("year")),
                                     int(request.GET.get("month")), 1)
                    else:
                        month = date.today().replace(day=1)
                    bill = create_client_bill_from_timesheet(mission, month)
                else:  # FIXED_PRICE mission
                    proportion = request.GET.get("proportion", 0.30)
                    bill = create_client_bill_from_proportion(
                        mission, proportion=proportion)

                form = ClientBillForm(instance=bill)
                billDetailFormSet = BillDetailFormSet(instance=bill)
                billExpenseFormSet = BillExpenseFormSet(instance=bill)
            else:
                form = ClientBillForm()
    return render(
        request, "billing/client_bill_form.html", {
            "bill_form": form,
            "detail_formset": billDetailFormSet,
            "detail_formset_helper": BillDetailFormSetHelper(),
            "expense_formset": billExpenseFormSet,
            "expense_formset_helper": BillExpenseFormSetHelper(),
            "bill_id": bill.id if bill else None,
            "can_delete": bill.state in wip_status if bill else False,
            "can_preview": bill.state in wip_status if bill else False,
            "user": request.user
        })