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)
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
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.'}
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)
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
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.'}
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.' }
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
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_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
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)
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
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)
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.'] })
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())
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
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)
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)
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
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
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.'] })
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.'] })
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
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)
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)
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())
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, [])
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)
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
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
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
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
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.']}
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
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)
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_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)
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)
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('_', ' ') ) )
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)