def test_get_invoice(self):
        InvoiceFactory.reset_sequence(1)
        InvoiceFactory.create()

        url = reverse('invoice-detail', kwargs={'pk': 1})
        response = self.client.get(url)

        assert response.status_code == status.HTTP_200_OK
        assert response.data == {
            "id": 1,
            "series": "InvoiceSeries",
            "number": 1,
            "provider": "http://testserver/providers/1/",
            "customer": "http://testserver/customers/1/",
            "archived_provider": {},
            "archived_customer": {},
            "due_date": None,
            "issue_date": None,
            "paid_date": None,
            "cancel_date": None,
            "sales_tax_name": "VAT",
            "sales_tax_percent": '1.00',
            "currency": "RON",
            "state": "draft",
            "proforma": None,
            "invoice_entries": [],
            "pdf_url": None,
            "total": Decimal('0.00'),
        }
Exemple #2
0
    def test_get_invoice(self):
        InvoiceFactory.reset_sequence(1)
        InvoiceFactory.create()

        url = reverse('invoice-detail', kwargs={'pk': 1})
        response = self.client.get(url)

        assert response.status_code == status.HTTP_200_OK
        assert response.data == {
            "id": 1,
            "series": "InvoiceSeries",
            "number": 1,
            "provider": "http://testserver/providers/1/",
            "customer": "http://testserver/customers/1/",
            "archived_provider": {},
            "archived_customer": {},
            "due_date": None,
            "issue_date": None,
            "paid_date": None,
            "cancel_date": None,
            "sales_tax_name": "VAT",
            "sales_tax_percent": '1.00',
            "currency": "RON",
            "state": "draft",
            "proforma": None,
            "invoice_entries": [],
            "pdf_url": None,
            "total": Decimal('0.00'),
        }
    def test_delete_invoice_entry(self):
        InvoiceFactory.create()

        url = reverse('invoice-entry-create', kwargs={'document_pk': 1})
        entry_data = {
            "description": "Page views",
            "unit_price": 10.0,
            "quantity": 20
        }
        entries_count = 10
        for cnt in range(entries_count):
            self.client.post(url,
                             data=json.dumps(entry_data),
                             content_type='application/json')

        url = reverse('invoice-entry-update',
                      kwargs={
                          'document_pk': 1,
                          'entry_pk': 1
                      })
        response = self.client.delete(url)
        assert response.status_code == status.HTTP_204_NO_CONTENT

        url = reverse('invoice-detail', kwargs={'pk': 1})
        response = self.client.get(url)
        invoice_entries = response.data.get('invoice_entries', None)
        assert len(invoice_entries) == entries_count - 1
    def test_issue_invoice_with_default_dates(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {'state': 'issued'}
        response = self.client.put(url,
                                   data=json.dumps(data),
                                   content_type='application/json')

        assert response.status_code == status.HTTP_200_OK
        due_date = timezone.now().date() + timedelta(days=PAYMENT_DUE_DAYS)
        mandatory_content = {
            'issue_date': timezone.now().date().strftime('%Y-%m-%d'),
            'due_date': due_date.strftime('%Y-%m-%d'),
            'state': 'issued'
        }
        assert response.status_code == status.HTTP_200_OK
        assert all(item in response.data.items()
                   for item in mandatory_content.iteritems())
        assert response.data.get('archived_provider', {}) != {}
        assert response.data.get('archived_customer', {}) != {}

        invoice = get_object_or_None(Invoice, pk=1)
    def test_issue_invoice_with_custom_issue_date_and_due_date(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {
            'state': 'issued',
            'issue_date': '2014-01-01',
            'due_date': '2014-01-20'
        }

        response = self.client.put(url,
                                   data=json.dumps(data),
                                   content_type='application/json')

        assert response.status_code == status.HTTP_200_OK
        mandatory_content = {
            'issue_date': '2014-01-01',
            'due_date': '2014-01-20',
            'state': 'issued'
        }
        assert response.status_code == status.HTTP_200_OK
        assert all(item in response.data.items()
                   for item in mandatory_content.iteritems())
        assert response.data.get('archived_provider', {}) != {}
        assert response.data.get('archived_customer', {}) != {}

        invoice = get_object_or_None(Invoice, pk=1)
Exemple #6
0
    def test_issue_invoice_with_custom_issue_date_and_due_date(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {
            'state': 'issued',
            'issue_date': '2014-01-01',
            'due_date': '2014-01-20'
        }

        response = self.client.put(url, data=json.dumps(data),
                                     content_type='application/json')

        assert response.status_code == status.HTTP_200_OK
        mandatory_content = {
            'issue_date': '2014-01-01',
            'due_date': '2014-01-20',
            'state': 'issued'
        }
        assert response.status_code == status.HTTP_200_OK
        assert all(item in response.data.items()
                   for item in mandatory_content.iteritems())
        assert response.data.get('archived_provider', {}) != {}
        assert response.data.get('archived_customer', {}) != {}

        invoice = get_object_or_None(Invoice, pk=1)
Exemple #7
0
    def test_actions_failed_no_log_entries(self):
        InvoiceFactory.create()

        url = reverse('admin:silver_invoice_changelist')

        mock_log_entry = MagicMock()
        mock_log_action = MagicMock()
        mock_log_entry.objects.log_action = mock_log_action

        exceptions = cycle([ValueError, TransitionNotAllowed])

        def _exception_thrower(*args):
            raise exceptions.next()

        mock_action = MagicMock(side_effect=_exception_thrower)

        mock_invoice = MagicMock()
        mock_invoice.issue = mock_action
        mock_invoice.cancel = mock_action
        mock_invoice.pay = mock_action
        mock_invoice.clone_into_draft = mock_action
        mock_invoice.create_invoice = mock_action

        with patch.multiple('silver.admin',
                            LogEntry=mock_log_entry,
                            Invoice=mock_invoice):
            actions = ['issue', 'pay', 'cancel', 'clone']

            for action in actions:
                self.admin.post(url, {
                    'action': action,
                    '_selected_action': [u'1']
                })

                assert not mock_log_action.call_count
Exemple #8
0
    def test_pay_invoice_when_in_draft_state(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {'state': 'paid'}
        response = self.client.put(url, data=json.dumps(data),
                                     content_type='application/json')
        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert response.data == {'detail': 'An invoice can be paid only if it is in issued state.'}
Exemple #9
0
    def test_get_invoices(self):
        batch_size = 50
        InvoiceFactory.create_batch(batch_size)

        url = reverse('invoice-list')
        response = self.client.get(url)

        self.assertEqual(response.status_code, status.HTTP_200_OK)

        response = self.client.get(url + '?page=2')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
Exemple #10
0
    def test_get_invoices(self):
        batch_size = 50
        InvoiceFactory.create_batch(batch_size)

        url = reverse('invoice-list')
        response = self.client.get(url)

        assert response.status_code == status.HTTP_200_OK

        response = self.client.get(url + '?page=2')

        assert response.status_code == status.HTTP_200_OK
Exemple #11
0
    def test_illegal_state_change_when_in_draft_state(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {'state': 'illegal-state'}

        response = self.client.put(url, data=json.dumps(data),
                                     content_type='application/json')

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert response.data == {'detail': 'Illegal state value.'}
Exemple #12
0
    def test_illegal_state_change_when_in_draft_state(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {'state': 'illegal-state'}

        response = self.client.put(url,
                                   data=json.dumps(data),
                                   content_type='application/json')

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert response.data == {'detail': 'Illegal state value.'}
Exemple #13
0
    def test_pay_invoice_when_in_draft_state(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {'state': 'paid'}
        response = self.client.put(url,
                                   data=json.dumps(data),
                                   content_type='application/json')
        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert response.data == {
            'detail': 'An invoice can be paid only if it is in issued state.'
        }
Exemple #14
0
    def test_invoice_due_today_queryset(self):
        invoices = InvoiceFactory.create_batch(5)

        invoices[0].state = Invoice.STATES.DRAFT
        invoices[0].due_date = date.today()
        invoices[0].save()

        invoices[1].state = Invoice.STATES.ISSUED
        invoices[1].due_date = date.today()
        invoices[1].save()

        invoices[2].state = Invoice.STATES.PAID
        invoices[2].due_date = date.today() - timedelta(days=1)
        invoices[2].save()

        invoices[3].state = Invoice.STATES.CANCELED
        invoices[3].due_date = date.today()
        invoices[3].save()

        invoices[4].state = Invoice.STATES.ISSUED
        invoices[4].due_date = date.today() + timedelta(days=1)
        invoices[4].save()

        queryset = Invoice.objects.due_today()

        assert queryset.count() == 1
        assert invoices[1] in queryset
Exemple #15
0
    def test_invoice_currency_used_for_transaction_currency(self):
        customer = CustomerFactory.create(currency=None)
        invoice = InvoiceFactory.create(customer=customer,
                                        currency='EUR',
                                        transaction_currency=None)

        self.assertEqual(invoice.transaction_currency, 'EUR')
Exemple #16
0
    def test_invoice_total_with_tax_integrity(self):
        invoice_entries = DocumentEntryFactory.create_batch(5)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        assert invoice.total == invoice.total_before_tax + invoice.tax_value
Exemple #17
0
    def test_invoice_create_storno_from_unallowed_states(self):
        invoice = InvoiceFactory.create()
        assert invoice.state == invoice.STATES.DRAFT
        self.assertRaises(ValueError, invoice.create_storno)

        invoice.issue()
        self.assertRaises(ValueError, invoice.create_storno)
def test_generate_pdf_task(mock_http_response, mock_get_template, settings,
                           tmpdir, monkeypatch):
    settings.MEDIA_ROOT = tmpdir.strpath

    invoice = InvoiceFactory.create()
    invoice.issue()

    assert invoice.pdf.dirty

    pisa_document_mock = MagicMock()

    monkeypatch.setattr('silver.models.documents.pdf.pisa.pisaDocument',
                        pisa_document_mock)

    generate_pdf(invoice.id, invoice.kind)

    # pdf needs to be refreshed as the invoice reference in the test is not the same with the one
    # in the task
    invoice.pdf.refresh_from_db()

    assert not invoice.pdf.dirty

    assert invoice.pdf.url == settings.MEDIA_URL + invoice.get_pdf_upload_path(
    )

    assert pisa_document_mock.call_count == 1

    pisa_document_mock.assert_called_once_with(
        src=mock_get_template().render().encode('UTF-8'),
        dest=mock_http_response(),
        encoding='UTF-8',
        link_callback=fetch_resources)
Exemple #19
0
def test_generate_pdf_task(settings, tmpdir, monkeypatch):
    settings.MEDIA_ROOT = tmpdir.strpath

    invoice = InvoiceFactory.create()
    invoice.issue()

    assert invoice.pdf.dirty

    pisa_document_mock = MagicMock(return_value=MagicMock(err=False))

    monkeypatch.setattr('silver.models.documents.pdf.pisa.pisaDocument',
                        pisa_document_mock)

    generate_pdf(invoice.id, invoice.kind)

    # pdf needs to be refreshed as the invoice reference in the test is not the same with the one
    # in the task
    invoice.pdf.refresh_from_db()

    assert not invoice.pdf.dirty

    assert invoice.pdf.url == settings.MEDIA_URL + invoice.get_pdf_upload_path()

    assert pisa_document_mock.call_count == 1

    assert len(pisa_document_mock.mock_calls) == 1
Exemple #20
0
    def test_documents_list_case_1(self):
        """
            One proforma, one invoice, without related documents
        """
        proforma = ProformaFactory.create()
        invoice = InvoiceFactory.create()
        invoice.issue()
        payment_method = PaymentMethodFactory.create(customer=invoice.customer)
        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        url = reverse('document-list')

        with patch('silver.utils.payments._get_jwt_token',
                   new=self._jwt_token):
            response = self.client.get(url)

        # ^ there's a bug where specifying format='json' doesn't work
        response_data = json.loads(json.dumps(response.data))

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response_data), 2)

        self.assertIn(self._get_expected_data(invoice, [transaction]),
                      response_data)

        self.assertIn(self._get_expected_data(proforma), response_data)
Exemple #21
0
    def test_patch_transaction_documents(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor='someprocessor'
        )
        transaction = TransactionFactory.create(payment_method=payment_method)
        proforma = ProformaFactory.create()
        invoice = InvoiceFactory.create(proforma=proforma)
        proforma.invoice = invoice
        proforma.save()

        invoice_url = reverse('invoice-detail', args=[invoice.pk])
        proforma_url = reverse('proforma-detail', args=[proforma.pk])
        url = reverse('transaction-detail', args=[transaction.customer.pk,
                                                  transaction.uuid])

        data = {
            'proforma': proforma_url,
            'invoice': invoice_url
        }

        response = self.client.patch(url, format='json', data=data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        self.assertEqual(response.data, {
            'proforma': [u'This field may not be modified.'],
            'invoice': [u'This field may not be modified.']
        })
Exemple #22
0
    def test_cancel_invoice_with_provided_date(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        invoice = InvoiceFactory.create(provider=provider, customer=customer)
        invoice.issue()
        invoice.save()

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {
            'state': 'canceled',
            'cancel_date': '2014-10-10'
        }

        response = self.client.put(url, data=json.dumps(data),
                                     content_type='application/json')

        assert response.status_code == status.HTTP_200_OK
        due_date = timezone.now().date() + timedelta(days=PAYMENT_DUE_DAYS)
        mandatory_content = {
            'issue_date': timezone.now().date().strftime('%Y-%m-%d'),
            'due_date': due_date.strftime('%Y-%m-%d'),
            'cancel_date': '2014-10-10',
            'state': 'canceled'
        }
        assert response.status_code == status.HTTP_200_OK
        assert all(item in response.data.items()
                   for item in mandatory_content.iteritems())
Exemple #23
0
    def test_create_negative_document(self):
        """ Confirm that an invoice can be issued with a negative value. """

        # 0 for easy asserting.
        customer = CustomerFactory(sales_tax_percent=0, currency='USD')

        entry = DocumentEntryFactory(quantity=1, unit_price=-150)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer)
        invoice.issue()

        customer = invoice.customer
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer,
            canceled=False)

        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=invoice.total_in_transaction_currency,
            state=Transaction.States.Initial)

        assert invoice.transactions.count() == 1
        assert invoice.total_in_transaction_currency == -150
        assert transaction.amount == -150
Exemple #24
0
    def test_documents_list_case_1(self):
        """
            One proforma, one invoice, without related documents
        """
        proforma = ProformaFactory.create()
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)
        invoice.issue()
        payment_method = PaymentMethodFactory.create(customer=invoice.customer)
        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        url = reverse('document-list')

        with patch('silver.utils.payments._get_jwt_token',
                   new=self._jwt_token):
            response = self.client.get(url)

        # ^ there's a bug where specifying format='json' doesn't work
        response_data = response.data

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response_data), 2)

        self.assertIn(self._get_expected_data(invoice, [transaction]),
                      response_data)

        self.assertIn(self._get_expected_data(proforma), response_data)
Exemple #25
0
    def test_invoice_total_with_tax_integrity(self):
        invoice_entries = DocumentEntryFactory.create_batch(5)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        self.assertEqual(invoice.total, invoice.total_before_tax + invoice.tax_value)
Exemple #26
0
    def test_invoice_tax_value_decimal_places(self):
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        assert self._get_decimal_places(invoice.tax_value) == 2
Exemple #27
0
    def test_add_invoice_entry_in_paid_state(self):
        invoice = InvoiceFactory.create()
        invoice.issue()
        invoice.pay()
        invoice.save()

        url = reverse('invoice-entry-create',
                      kwargs={'document_pk': invoice.pk})
        entry_data = {
            "description": "Page views",
            "unit_price": 10.0,
            "quantity": 20
        }
        response = self.client.post(url,
                                    data=json.dumps(entry_data),
                                    content_type='application/json')

        assert response.status_code == status.HTTP_403_FORBIDDEN
        msg = 'Invoice entries can be added only when the invoice is in draft state.'
        assert response.data == {'detail': msg}

        url = reverse('invoice-detail', kwargs={'pk': invoice.pk})
        response = self.client.get(url)
        invoice_entries = response.data.get('invoice_entries', None)
        assert len(invoice_entries) == 0
Exemple #28
0
    def test_patch_transaction_documents(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor='someprocessor')
        transaction = TransactionFactory.create(payment_method=payment_method)
        proforma = ProformaFactory.create()
        invoice = InvoiceFactory.create(proforma=proforma)
        proforma.invoice = invoice
        proforma.save()

        invoice_url = reverse('invoice-detail', args=[invoice.pk])
        proforma_url = reverse('proforma-detail', args=[proforma.pk])
        url = reverse('transaction-detail',
                      args=[transaction.customer.pk, transaction.uuid])

        data = {'proforma': proforma_url, 'invoice': invoice_url}

        response = self.client.patch(url, format='json', data=data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        self.assertEqual(
            response.data, {
                'proforma': [u'This field may not be modified.'],
                'invoice': [u'This field may not be modified.']
            })
Exemple #29
0
    def test_post_payment_with_invalid_fields(self):
        invoice = InvoiceFactory.create()
        customer = invoice.customer

        url = reverse('payment-list', kwargs={'customer_pk': customer.pk})

        data = {
            'due_date': "yesterday",
            'visible': "maybe",
            'amount': -10.00,
            'currency': 'USD',
            'status': 'prepaid',
            'provider': 'http://testserver/providers/1234/',
            'invoice': 'http://testserver/invoices/4321/'
        }

        response = self.client.post(url,
                                    json.dumps(data),
                                    content_type='application/json')

        assert response.status_code == status.HTTP_400_BAD_REQUEST

        self.assertEquals(
            response.data, {
                'status': [u'"prepaid" is not a valid choice.'],
                'due_date': [
                    u'Date has wrong format. '
                    u'Use one of these formats instead: YYYY[-MM[-DD]].'
                ],
                'visible': [u'"maybe" is not a valid boolean.'],
                'amount':
                [u'Ensure this value is greater than or equal to 0.00.'],
                'invoice': [u'Invalid hyperlink - Object does not exist.'],
                'provider': [u'Invalid hyperlink - Object does not exist.']
            })
Exemple #30
0
    def test_invoice_currency_used_for_transaction_currency(self):
        customer = CustomerFactory.create(currency=None)
        invoice = InvoiceFactory.create(customer=customer,
                                        currency='EUR',
                                        transaction_currency=None)

        self.assertEqual(invoice.transaction_currency, 'EUR')
def test_generate_pdf_task(settings, tmpdir, monkeypatch):
    settings.MEDIA_ROOT = tmpdir.strpath

    invoice = InvoiceFactory.create()
    invoice.issue()

    assert invoice.pdf.dirty

    generate_pdf_mock = MagicMock()

    monkeypatch.setattr(
        'silver.models.documents.pdf.generate_pdf_template_object',
        generate_pdf_mock)

    generate_pdf(invoice.id, invoice.kind)

    # pdf needs to be refreshed as the invoice reference in the test is not the same with the one
    # in the task
    invoice.pdf.refresh_from_db()

    assert not invoice.pdf.dirty

    assert invoice.pdf.url == settings.MEDIA_URL + invoice.get_pdf_upload_path(
    )

    assert generate_pdf_mock.call_count == 1
Exemple #32
0
    def test_add_transaction_with_unrelated_documents(self):
        customer = CustomerFactory.create()
        payment_method = PaymentMethodFactory.create(customer=customer)

        invoice = InvoiceFactory.create(customer=customer)
        invoice.issue()

        proforma = ProformaFactory.create(customer=customer)
        proforma.issue()

        valid_until = datetime.now().replace(microsecond=0)
        url = reverse('payment-method-transaction-list',
                      kwargs={'customer_pk': customer.pk,
                              'payment_method_id': payment_method.pk})

        invoice_url = reverse('invoice-detail', args=[invoice.pk])
        proforma_url = reverse('proforma-detail', args=[proforma.pk])
        data = {
            'payment_method': reverse('payment-method-detail',
                                      kwargs={'customer_pk': customer.pk,
                                              'payment_method_id': payment_method.id}),
            'valid_until': valid_until,
            'amount': 200.0,
            'invoice': invoice_url,
            'proforma': proforma_url
        }

        response = self.client.post(url, format='json', data=data)

        expected_data = {
            'non_field_errors': [u'Invoice and proforma are not related.']
        }
        self.assertEqual(response.data, expected_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemple #33
0
    def test_add_transaction_with_unrelated_documents(self):
        customer = CustomerFactory.create()
        payment_method = PaymentMethodFactory.create(customer=customer)

        invoice = InvoiceFactory.create(customer=customer)
        proforma = ProformaFactory.create(customer=customer)
        valid_until = datetime.now()
        url = reverse('payment-method-transaction-list',
                      kwargs={'customer_pk': customer.pk, 'payment_method_id': payment_method.pk})
        invoice_url = reverse('invoice-detail', args=[invoice.pk])
        proforma_url = reverse('proforma-detail', args=[proforma.pk])
        data = {
            'payment_method': reverse('payment-method-detail', kwargs={'customer_pk': customer.pk,
                                                                       'payment_method_id': payment_method.id}),
            'valid_until': valid_until,
            'amount': 200.0,
            'invoice': invoice_url,
            'proforma': proforma_url
        }

        response = self.client.post(url, format='json', data=data)

        expected_data = {
            'non_field_errors': [u'Invoice and proforma are not related.']
        }
        self.assertEqual(response.data, expected_data)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemple #34
0
    def test_invoice_tax_value_decimal_places(self):
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        assert self._get_decimal_places(invoice.tax_value) == 2
Exemple #35
0
    def test_cancel_invoice_with_provided_date(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        invoice = InvoiceFactory.create(provider=provider, customer=customer)
        invoice.issue()
        invoice.save()

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {'state': 'canceled', 'cancel_date': '2014-10-10'}

        response = self.client.put(url,
                                   data=json.dumps(data),
                                   content_type='application/json')

        assert response.status_code == status.HTTP_200_OK
        due_date = timezone.now().date() + timedelta(days=PAYMENT_DUE_DAYS)
        mandatory_content = {
            'issue_date': timezone.now().date().strftime('%Y-%m-%d'),
            'due_date': due_date.strftime('%Y-%m-%d'),
            'cancel_date': '2014-10-10',
            'state': 'canceled'
        }
        assert response.status_code == status.HTTP_200_OK
        assert all(item in response.data.items()
                   for item in mandatory_content.iteritems())
Exemple #36
0
    def test_invoice_due_today_queryset(self):
        invoices = InvoiceFactory.create_batch(5)

        invoices[0].state = Invoice.STATES.DRAFT
        invoices[0].due_date = date.today()
        invoices[0].save()

        invoices[1].state = Invoice.STATES.ISSUED
        invoices[1].due_date = date.today()
        invoices[1].save()

        invoices[2].state = Invoice.STATES.PAID
        invoices[2].due_date = date.today() - timedelta(days=1)
        invoices[2].save()

        invoices[3].state = Invoice.STATES.CANCELED
        invoices[3].due_date = date.today()
        invoices[3].save()

        invoices[4].state = Invoice.STATES.ISSUED
        invoices[4].due_date = date.today() + timedelta(days=1)
        invoices[4].save()

        queryset = Invoice.objects.due_today()

        assert queryset.count() == 1
        assert invoices[1] in queryset
Exemple #37
0
    def test_add_single_invoice_entry(self):
        InvoiceFactory.create_batch(10)

        url = reverse('invoice-entry-create', kwargs={'document_pk': 1})
        entry_data = {
            "description": "Page views",
            "unit_price": 10.0,
            "quantity": 20
        }
        response = self.client.post(url,
                                    data=json.dumps(entry_data),
                                    content_type='application/json')

        invoice = Invoice.objects.get(pk=1)
        total = Decimal(200.0) * Decimal(1 + invoice.sales_tax_percent / 100)

        assert response.status_code == status.HTTP_201_CREATED
        assert response.data == {
            'description': 'Page views',
            'unit': None,
            'quantity': '20.0000',
            'unit_price': '10.0000',
            'start_date': None,
            'end_date': None,
            'prorated': False,
            'product_code': None,
            'total': total,
            'total_before_tax': Decimal(200.0)
        }

        url = reverse('invoice-detail', kwargs={'pk': 1})
        response = self.client.get(url)

        invoice_entries = response.data.get('invoice_entries', None)
        assert len(invoice_entries) == 1
        assert invoice_entries[0] == {
            'description': 'Page views',
            'unit': None,
            'quantity': '20.0000',
            'unit_price': '10.0000',
            'start_date': None,
            'end_date': None,
            'prorated': False,
            'product_code': None,
            'total': total,
            'total_before_tax': Decimal(200.0)
        }
    def test_filter_min_max_amount(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, )
        customer = payment_method.customer

        entry = DocumentEntryFactory(quantity=1, unit_price=100)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer)
        invoice.issue()

        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        transaction_data = self._transaction_data(transaction)

        urls = [
            reverse('payment-method-transaction-list',
                    kwargs={
                        'customer_pk': customer.pk,
                        'payment_method_id': payment_method.pk
                    }),
            reverse('transaction-list', kwargs={'customer_pk': customer.pk})
        ]

        for url in urls:
            url_with_filterable_data = url + '?min_amount=10'
            url_no_output = url + '?min_amount=150'

            with patch('silver.utils.payments._get_jwt_token') as mocked_token:
                mocked_token.return_value = 'token'

                response = self.client.get(url_with_filterable_data,
                                           format='json')

                transaction.refresh_from_db()
                transaction_data['updated_at'] = response.data[0]['updated_at']

                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data[0], transaction_data)

                response = self.client.get(url_no_output, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, [])

                url_with_filterable_data = url + '?max_amount=1050'
                url_no_output = url + '?max_amount=10'

                response = self.client.get(url_with_filterable_data,
                                           format='json')

                transaction.refresh_from_db()
                transaction_data['updated_at'] = response.data[0]['updated_at']

                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data[0], transaction_data)

                response = self.client.get(url_no_output, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, [])
Exemple #39
0
    def test_add_single_invoice_entry(self):
        InvoiceFactory.create_batch(10)

        url = reverse('invoice-entry-create', kwargs={'document_pk': 1})
        entry_data = {
            "description": "Page views",
            "unit_price": 10.0,
            "quantity": 20
        }
        response = self.client.post(url, data=json.dumps(entry_data),
                                    content_type='application/json')

        invoice = Invoice.objects.get(pk=1)
        total = Decimal(200.0) * Decimal(1 + invoice.sales_tax_percent / 100)

        assert response.status_code == status.HTTP_201_CREATED
        assert response.data == {
            'description': 'Page views',
            'unit': None,
            'quantity': '20.0000',
            'unit_price': '10.0000',
            'start_date': None,
            'end_date': None,
            'prorated': False,
            'product_code': None,
            'total': total,
            'total_before_tax': Decimal(200.0)
        }

        url = reverse('invoice-detail', kwargs={'pk': 1})
        response = self.client.get(url)

        invoice_entries = response.data.get('invoice_entries', None)
        assert len(invoice_entries) == 1
        assert invoice_entries[0] == {
            'description': 'Page views',
            'unit': None,
            'quantity': '20.0000',
            'unit_price': '10.0000',
            'start_date': None,
            'end_date': None,
            'prorated': False,
            'product_code': None,
            'total': total,
            'total_before_tax': Decimal(200.0)
        }
Exemple #40
0
    def handle(self, *args, **options):
        proforma = ProformaFactory.create(proforma_entries=[DocumentEntryFactory.create()],
                                          state=Proforma.STATES.ISSUED)
        proforma.create_invoice()

        invoice = InvoiceFactory.create(invoice_entries=[DocumentEntryFactory.create()],
                                        state=Invoice.STATES.ISSUED,
                                        related_document=None)
        TransactionFactory.create(state=Transaction.States.Settled,
                                  invoice=invoice,
                                  payment_method__customer=invoice.customer,
                                  proforma=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.PAID,
                                    related_document=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.DRAFT,
                                    related_document=None)

        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.CANCELED,
                                    related_document=None)
Exemple #41
0
    def handle(self, *args, **options):
        proforma = ProformaFactory.create(proforma_entries=[DocumentEntryFactory.create()],
                                          state=Proforma.STATES.ISSUED)
        proforma.create_invoice()

        invoice = InvoiceFactory.create(invoice_entries=[DocumentEntryFactory.create()],
                                        state=Invoice.STATES.ISSUED,
                                        related_document=None)
        TransactionFactory.create(state=Transaction.States.Settled,
                                  invoice=invoice,
                                  payment_method__customer=invoice.customer,
                                  proforma=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.PAID,
                                    related_document=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.DRAFT,
                                    related_document=None)

        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.CANCELED,
                                    related_document=None)
Exemple #42
0
    def test_draft_invoice_series_number(self):
        invoice = InvoiceFactory.create()
        invoice.number = None

        assert invoice.series_number == '%s-draft-id:%d' % (invoice.series,
                                                            invoice.pk)

        invoice.series = None

        assert invoice.series_number == 'draft-id:%d' % invoice.pk
Exemple #43
0
    def test_invoice_storno_issue(self):
        invoice = InvoiceFactory.create()
        invoice.issue()
        invoice.pay()
        storno = invoice.create_storno()

        storno.issue()
        assert storno.state == storno.STATES.ISSUED
        assert storno.issue_date == date.today()
        assert not storno.due_date
Exemple #44
0
    def test_draft_invoice_series_number(self):
        invoice = InvoiceFactory.create()
        invoice.number = None

        assert invoice.series_number == '%s-draft-id:%d' % (invoice.series,
                                                            invoice.pk)

        invoice.series = None

        assert invoice.series_number == 'draft-id:%d' % invoice.pk
Exemple #45
0
    def test_invoice_create_storno_from_paid_state(self):
        invoice = InvoiceFactory.create(
            invoice_entries=[DocumentEntryFactory.create()])
        invoice.issue()
        invoice.pay()
        storno = invoice.create_storno()

        assert -invoice.total == storno.total != 0
        assert storno.related_document == invoice
        assert invoice.customer == storno.customer
        assert invoice.provider == storno.provider
Exemple #46
0
    def test_post_get_payments(self):
        invoice = InvoiceFactory.create()
        customer = invoice.customer

        url = reverse('payment-list',
                      kwargs={'customer_pk': invoice.customer.pk})

        data = {
            'due_date': None,
            'visible': True,
            'amount': 10.00,
            'currency': 'USD',
            'status': 'unpaid',
            'provider':
            'http://testserver/providers/%d/' % invoice.provider.pk,
            'invoice': 'http://testserver/invoices/%d/' % invoice.pk
        }

        payment = self.client.post(url,
                                   json.dumps(data),
                                   content_type='application/json').data
        payment_url = 'http://testserver/customers/%d/payments/%d/' % (
            customer.pk, payment['id'])

        expected_data = [{
            'customer':
            'http://testserver/customers/%d/' % customer.pk,
            'due_date':
            None,
            'proforma':
            None,
            'visible':
            True,
            'url':
            payment_url,
            'amount':
            u'10.00',
            'currency':
            u'USD',
            'status':
            'unpaid',
            'invoice':
            'http://testserver/invoices/%d/' % invoice.pk,
            'provider':
            'http://testserver/providers/%d/' % invoice.provider.pk,
            'id':
            payment['id']
        }]

        response = self.client.get(url, content_type='application/json')

        assert response.status_code == status.HTTP_200_OK
        assert response.data == expected_data
Exemple #47
0
    def test_edit_invoice_in_issued_state(self):
        invoice = InvoiceFactory.create()
        invoice.issue()
        invoice.save()

        url = reverse('invoice-detail', kwargs={'pk': 1})
        data = {"description": "New Page views"}
        response = self.client.patch(url, data=json.dumps(data),
                                     content_type='application/json')

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert response.data == {'non_field_errors': ['You cannot edit the document once it is in issued state.']}
Exemple #48
0
    def test_invoice_overdue_since_last_month_queryset(self):
        invoices = InvoiceFactory.create_batch(3)

        invoices[0].due_date = date.today().replace(day=1)
        invoices[0].issue()

        invoices[1].due_date = date.today() - timedelta(days=31)
        invoices[1].issue()

        queryset = Invoice.objects.overdue_since_last_month()

        assert queryset.count() == 1
        assert invoices[1] in queryset
def test_generate_pdfs_task(monkeypatch):
    issued_invoice = InvoiceFactory.create()
    issued_invoice.issue()

    paid_invoice = InvoiceFactory.create()
    paid_invoice.issue()
    paid_invoice.pay()

    canceled_invoice = InvoiceFactory.create()
    canceled_invoice.issue()
    canceled_invoice.cancel()

    issued_invoice_already_generated = InvoiceFactory.create()
    issued_invoice_already_generated.issue()
    issued_invoice_already_generated.pdf.dirty = False
    issued_invoice_already_generated.pdf.save()

    issued_proforma = ProformaFactory.create()
    issued_proforma.issue()

    issued_proforma_already_generated = ProformaFactory.create()
    issued_proforma_already_generated.issue()
    issued_proforma_already_generated.pdf.dirty = False
    issued_proforma_already_generated.pdf.save()

    documents_to_generate = [issued_invoice, canceled_invoice, paid_invoice,
                             issued_proforma]

    for document in documents_to_generate:
        assert document.pdf.dirty

    lock_mock = MagicMock()
    monkeypatch.setattr('silver.tasks.redis.lock', lock_mock)

    with patch('silver.tasks.group') as group_mock:
        generate_pdfs()

        assert group_mock.call_count
Exemple #50
0
    def test_documents_list_case_2(self):
        """
            One proforma with a related invoice, one invoice
        """
        proforma = ProformaFactory.create()
        invoice1 = InvoiceFactory.create(related_document=proforma)
        proforma.related_document = invoice1
        proforma.save()

        invoice2 = InvoiceFactory.create()

        url = reverse('document-list')
        response = self.client.get(url)

        # ^ there's a bug where specifying format='json' doesn't work
        response_data = json.loads(json.dumps(response.data))

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response_data), 2)

        self.assertIn(self._get_expected_data(invoice1), response_data)

        self.assertIn(self._get_expected_data(invoice2), response_data)
Exemple #51
0
    def test_delete_invoice_entry(self):
        InvoiceFactory.create()

        url = reverse('invoice-entry-create', kwargs={'document_pk': 1})
        entry_data = {
            "description": "Page views",
            "unit_price": 10.0,
            "quantity": 20
        }
        entries_count = 10
        for cnt in range(entries_count):
            self.client.post(url, data=json.dumps(entry_data),
                             content_type='application/json')

        url = reverse('invoice-entry-update', kwargs={'document_pk': 1,
                                                      'entry_pk': 1})
        response = self.client.delete(url)
        assert response.status_code == status.HTTP_204_NO_CONTENT

        url = reverse('invoice-detail', kwargs={'pk': 1})
        response = self.client.get(url)
        invoice_entries = response.data.get('invoice_entries', None)
        assert len(invoice_entries) == entries_count - 1
Exemple #52
0
    def test_issue_invoice_with_default_dates(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        InvoiceFactory.create(provider=provider, customer=customer)

        url = reverse('invoice-state', kwargs={'pk': 1})
        data = {'state': 'issued'}
        response = self.client.put(url, data=json.dumps(data),
                                     content_type='application/json')

        assert response.status_code == status.HTTP_200_OK
        due_date = timezone.now().date() + timedelta(days=PAYMENT_DUE_DAYS)
        mandatory_content = {
            'issue_date': timezone.now().date().strftime('%Y-%m-%d'),
            'due_date': due_date.strftime('%Y-%m-%d'),
            'state': 'issued'
        }
        assert response.status_code == status.HTTP_200_OK
        assert all(item in response.data.items()
                   for item in mandatory_content.iteritems())
        assert response.data.get('archived_provider', {}) != {}
        assert response.data.get('archived_customer', {}) != {}

        invoice = get_object_or_None(Invoice, pk=1)
    def test_create_transactions_on_payment_method_verify(self):
        customer = CustomerFactory.create()

        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer,
            canceled=False,
            verified=False
        )

        lone_invoice = InvoiceFactory.create(
            transaction_currency='USD',
            transaction_xe_rate=Decimal('1.0'),
            state=Invoice.STATES.ISSUED,
            customer=customer
        )

        lone_proforma = ProformaFactory.create(
            transaction_currency='USD',
            transaction_xe_rate=Decimal('1.0'),
            state=Proforma.STATES.ISSUED,
            customer=customer
        )

        paired_proforma = ProformaFactory.create(
            transaction_currency='USD',
            transaction_xe_rate=Decimal('1.0'),
            state=Proforma.STATES.ISSUED,
            issue_date=timezone.now().date(),
            customer=customer
        )
        paired_invoice = paired_proforma.create_invoice()

        self.assertEqual(payment_method.transactions.count(), 0)

        payment_method.verified = True
        payment_method.save()

        self.assertEqual(lone_invoice.transactions.count(), 1)

        self.assertEqual(lone_proforma.transactions.count(), 1)

        self.assertEqual(list(paired_invoice.transactions),
                         list(paired_proforma.transactions))

        self.assertEqual(paired_invoice.transactions.count(), 1)
Exemple #54
0
    def test_cancel_invoice_in_canceled_state(self):
        provider = ProviderFactory.create()
        customer = CustomerFactory.create()
        invoice = InvoiceFactory.create(provider=provider, customer=customer)
        invoice.issue()
        invoice.cancel()

        url = reverse('invoice-state', kwargs={'pk': invoice.pk})
        data = {'state': 'canceled'}

        response = self.client.put(url, data=json.dumps(data),
                                   content_type='application/json')

        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert response.data == {
            'detail': 'An invoice can be canceled only if it is in issued state.'
        }
    def test_no_transaction_creation_for_issued_documents_case3(self):
        """
            There are 1 pending and 1 settled transactions that together cover the document amount.
        """
        entry = DocumentEntryFactory(quantity=1, unit_price=100)
        invoice = InvoiceFactory.create(invoice_entries=[entry])
        invoice.issue()

        customer = invoice.customer
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, customer=customer,
            canceled=False,
            verified=False,
        )

        TransactionFactory.create(invoice=invoice,
                                  payment_method=payment_method,
                                  amount=invoice.total_in_transaction_currency / 2,
                                  state=Transaction.States.Settled)

        TransactionFactory.create(invoice=invoice,
                                  payment_method=payment_method,
                                  amount=invoice.total_in_transaction_currency / 2,
                                  state=Transaction.States.Pending)

        mock_execute = MagicMock()
        with patch.multiple(TriggeredProcessor, execute_transaction=mock_execute):
            expected_exception = ValidationError
            expected_message = "Amount is greater than the amount that should be " \
                               "charged in order to pay the billing document."
            try:
                TransactionFactory.create(invoice=invoice,
                                          payment_method=payment_method,
                                          amount=1)

                self.fail('{} not raised.'.format(str(expected_exception)))
            except expected_exception as e:
                self.assertTrue(expected_message in str(e))

            transactions = Transaction.objects.filter(
                payment_method=payment_method, invoice=invoice,
            )
            self.assertEqual(len(transactions), 2)

            self.assertEqual(mock_execute.call_count, 0)
Exemple #56
0
    def test_actions_log_entries(self):
        invoice = InvoiceFactory.create()

        url = reverse('admin:silver_invoice_changelist')

        mock_log_entry = MagicMock()
        mock_log_action = MagicMock()
        mock_log_entry.objects.log_action = mock_log_action

        mock_action = MagicMock(return_value=MagicMock(series_number='aaa'))

        mock_invoice = MagicMock()
        mock_invoice.issue = mock_action
        mock_invoice.cancel = mock_action
        mock_invoice.pay = mock_action
        mock_invoice.clone_into_draft = mock_action

        with patch.multiple('silver.admin',
                            LogEntry=mock_log_entry,
                            Invoice=mock_invoice):
            actions = ['issue', 'pay', 'cancel', 'clone']

            for action in actions:
                self.admin.post(url, {
                    'action': action,
                    '_selected_action': [u'1']
                })

                assert mock_action.call_count

                mock_action.reset_mock()

                if action == 'clone':
                    action = 'clone_into_draft'

                mock_log_action.assert_called_with(
                    user_id=1,
                    content_type_id=ContentType.objects.get_for_model(invoice).pk,
                    object_id=1,
                    object_repr=unicode(invoice),
                    action_flag=CHANGE,
                    change_message='{action} action initiated by user.'.format(
                        action=action.capitalize().replace('_', ' ')
                    )
                )
Exemple #57
0
    def test_invoice_overdue_queryset(self):
        invoices = InvoiceFactory.create_batch(3)

        invoices[0].due_date = date.today() - timedelta(days=1)
        invoices[0].issue()

        invoices[1].due_date = date.today() - timedelta(days=3)
        invoices[1].issue()

        invoices[2].due_date = date.today() - timedelta(days=31)
        invoices[2].issue()
        invoices[2].pay()

        queryset = Invoice.objects.overdue()

        assert queryset.count() == 2
        for invoice in invoices[:2]:
            assert invoice in queryset
    def test_no_transaction_creation_for_issued_documents_case2(self):
        """
            The payment method is not usable
        """
        invoice = InvoiceFactory.create()
        customer = invoice.customer
        PaymentMethodFactory.create(
            payment_processor=triggered_processor, customer=customer,
            canceled=False
        )

        mock_execute = MagicMock()
        with patch.multiple(TriggeredProcessor, execute_transaction=mock_execute):
            invoice.issue()

            transactions = Transaction.objects.filter(
                invoice=invoice, proforma=invoice.related_document
            )
            self.assertEqual(len(transactions), 0)