def test_invoice_change_status_in_db(self, status, _): self.client.force_login(self.ap_user) self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(status), }) invoice = get_object_or_404(Invoice, pk=self.invoice.id) self.assertEqual(invoice.status, invoice_status_lookup(status))
def test_invoices_list_filter_status(self): self.client.force_login(self.ap_user) invoice_approved = InvoiceFactory(user=self.user, taxpayer=self.taxpayer, invoice_number='4321') invoice_approved.status = invoice_status_lookup( INVOICE_STATUS_APPROVED) invoice_approved.save() response = self.client.get('{}?{}'.format( reverse('invoices-list'), 'status={}'.format( invoice_status_lookup(INVOICE_STATUS_APPROVED)))) self.assertContains(response, invoice_approved.invoice_number) self.assertNotContains(response, self.invoice.invoice_number)
def test_ap_invoices_list_are_in_new_status(self): self.client.force_login(self.ap_user) self.invoice_from_other_user.status = invoice_status_lookup( INVOICE_STATUS_REJECTED) self.invoice_from_other_user.save() response = self.client.get('{}?{}'.format( reverse('invoices-list'), 'status={}'.format(invoice_status_lookup(INVOICE_STATUS_PENDING)))) # Only the invoice with PENDING status should be listed self.assertNotContains(response, self.invoice_from_other_user.invoice_number) self.assertContains(response, self.invoice.invoice_number)
def test_invoice_in_progress_in_db(self): self.client.force_login(self.ap_user) self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS), 'workday_id': 123123, }, follow=True) invoice = get_object_or_404(Invoice, pk=self.invoice.id) self.assertEqual(invoice.status, invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS)) self.assertEqual(invoice.workday_id, '123123')
def user_has_permission(self): if not self.request.user.has_perm(CAN_CHANGE_INVOICE_STATUS_PERM): # Only allow supplier to edit the invoice if status is 'CHANGES REQUEST' invoice = get_object_or_404(Invoice, id=self.kwargs['pk']) return invoice.status == invoice_status_lookup(INVOICE_STATUS_CHANGES_REQUEST) return True
def test_invoice_request_changes_comment_with_reason(self): self.client.force_login(self.ap_user) message = 'test reason' response = self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_CHANGES_REQUEST), 'message': message, }) comment = invoice_history_comments(self.invoice)[-1] self.assertEqual(HTTPStatus.FOUND, response.status_code) self.assertIn( '{} from {} to {}'.format( 'Status', INVOICE_STATUS_PENDING, INVOICE_STATUS_CHANGES_REQUEST, ), comment.message, ) self.assertIn( message, comment.message, ) self.assertEqual(comment.user, self.ap_user)
def test_supplier_invoice_edit_and_it_exists_a_new_comment(self): # Given an invoice and a logged Supplier # invoice : self.invoice self.client.force_login(self.user) old_invoice_number = self.invoice.invoice_number self.invoice.status = invoice_status_lookup( INVOICE_STATUS_CHANGES_REQUEST) self.invoice.save() # When a supplier edits the invoice response = self.client.post( reverse('taxpayer-invoice-update', kwargs={ 'taxpayer_id': self.taxpayer.id, 'pk': self.invoice.id }), self.invoice_post_data) # Then the invoice should have a comment associated to it with its message comment = invoice_history_comments(self.invoice)[-1] self.assertIn( '{} from 1234 to 987654321'.format( 'Invoice Number', old_invoice_number, self.invoice.invoice_number, ), comment.message, ) self.assertEqual(comment.user, self.user) self.assertEqual(HTTPStatus.FOUND, response.status_code)
def test_invoice_change_status_only_ap_fail(self): self.client.force_login(self.user) request = self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_APPROVED), }) self.assertEqual(request.status_code, HTTPStatus.FORBIDDEN)
def test_invoice_change_status_code(self, id, expected, _): self.client.force_login(self.ap_user) request = self.client.post( reverse('change-invoice-status', kwargs={ 'pk': id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_REJECTED), }) self.assertEqual(request.status_code, expected)
def test_invoice_change_status_code_to_approved(self): self.client.force_login(self.ap_user) request = self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_APPROVED), 'workday_id': 123123, }) self.assertEqual(request.status_code, 302)
def test_invoice_change_status_to_approved_no_workday_id(self): self.client.force_login(self.ap_user) request = self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS), }, follow=True) self.assertContains(request, NO_WORKDAY_ID_ERROR)
def test_supplier_invoice_edit(self): self.client.force_login(self.user) self.invoice.status = invoice_status_lookup( INVOICE_STATUS_CHANGES_REQUEST) self.invoice.save() res = self.client.post( reverse('taxpayer-invoice-update', kwargs={ 'taxpayer_id': self.taxpayer.id, 'pk': self.invoice.id }), self.invoice_post_data, ) self.assertEqual(res.status_code, HTTPStatus.FOUND) self.invoice.refresh_from_db() self.assertEqual(self.invoice.invoice_number, self.invoice_post_data['invoice_number']) self.assertEqual(self.invoice.status, invoice_status_lookup(INVOICE_STATUS_PENDING))
def test_invoice_create_view(self): self.client.force_login(self.user) response = self.client.post( reverse('invoice-create', kwargs={'taxpayer_id': self.taxpayer.id}), self.invoice_post_data, ) self.assertEqual(response.status_code, HTTPStatus.FOUND) invoice = Invoice.objects.get( invoice_number=self.invoice_post_data['invoice_number']) self.assertEqual(invoice.status, invoice_status_lookup(INVOICE_STATUS_PENDING))
def test_invoice_request_changes_without_comment(self): self.client.force_login(self.ap_user) response = self.client.post(reverse( 'change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_CHANGES_REQUEST), }, follow=True) self.assertEqual(HTTPStatus.OK, response.status_code) self.assertContains(response, NO_COMMENT_ERROR)
def test_ap_invoice_edit(self): self.client.force_login(self.ap_user) res = self.client.post( reverse('invoice-update', kwargs={'pk': self.invoice.id}), self.invoice_post_data, ) self.assertEqual(res.status_code, HTTPStatus.FOUND) self.invoice.refresh_from_db() self.assertEqual(self.invoice.invoice_number, self.invoice_post_data['invoice_number']) self.assertEqual(self.invoice.status, invoice_status_lookup(INVOICE_STATUS_PENDING))
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) invoice = get_object_or_404(Invoice, id=self.kwargs['pk']) if self.request.user.is_AP: if invoice.new_comment_from_supplier is True: invoice.new_comment_from_supplier = False invoice.save() elif self.request.user.is_supplier: if invoice.new_comment_from_ap is True: invoice.new_comment_from_ap = False invoice.save() context['invoice'] = invoice father_taxpayer = get_object_or_404(TaxPayer, id=self.kwargs['taxpayer_id']) context['is_AP'] = self.request.user.is_AP context['taxpayer'] = father_taxpayer.get_taxpayer_child() context['address'] = Address.objects.get(taxpayer=father_taxpayer.get_taxpayer_child()) context['INVOICE_STATUS_APPROVED'] = invoice_status_lookup(INVOICE_STATUS_APPROVED) context['INVOICE_STATUS_PENDING'] = invoice_status_lookup(INVOICE_STATUS_PENDING) context['INVOICE_STATUS_CHANGES_REQUEST'] = invoice_status_lookup(INVOICE_STATUS_CHANGES_REQUEST) context['INVOICE_STATUS_REJECTED'] = invoice_status_lookup(INVOICE_STATUS_REJECTED) context['INVOICE_STATUS_PAID'] = invoice_status_lookup(INVOICE_STATUS_PAID) context['INVOICE_STATUS_IN_PROGRESS'] = invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS) context['comments'] = self.get_comments(invoice) context['date_format'] = DATE_FORMAT return context
def test_invoice_change_status_repeated_workday_id(self): self.client.force_login(self.ap_user) self.invoice.workday_id = 'G-180' self.invoice.save() response = self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), { 'status': invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS), 'workday_id': "G-180", }, follow=True) self.assertContains(response, 'Workday ID already exist')
def change_invoice_status(request, pk): status = request.POST.get('status') if status not in INVOICE_STATUSES_DICT.keys(): return HttpResponseBadRequest() strategy = get_change_status_strategy(status) invoice = get_object_or_404(Invoice, pk=pk) try: strategy(invoice, status, request) except ValidationError as err: messages.error(request, err.message) return redirect( reverse( 'invoices-detail', kwargs={ 'taxpayer_id': invoice.taxpayer.id, 'pk': pk, } ) ) except IntegrityError as err: messages.error(request, err) return redirect( reverse( 'invoices-detail', kwargs={ 'taxpayer_id': invoice.taxpayer.id, 'pk': pk, } ) ) invoice.save() invoice_changed = _('Invoice status has changed to ') messages.success( request, f'{invoice_changed}{INVOICE_STATUSES_DICT[status]}', ) if status != INVOICE_STATUS_PENDING_CODE: _send_email_when_change_invoice_status(request, invoice) return redirect( '{}?status={}'.format( reverse('invoices-list'), invoice_status_lookup(INVOICE_STATUS_PENDING) ) )
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['date_format'] = str(DATE_FORMAT) context['INVOICE_STATUS_APPROVED'] = invoice_status_lookup(INVOICE_STATUS_APPROVED) context['INVOICE_STATUS_PENDING'] = invoice_status_lookup(INVOICE_STATUS_PENDING) context['INVOICE_STATUS_CHANGES_REQUEST'] = invoice_status_lookup(INVOICE_STATUS_CHANGES_REQUEST) context['INVOICE_STATUS_REJECTED'] = invoice_status_lookup(INVOICE_STATUS_REJECTED) context['INVOICE_STATUS_PAID'] = invoice_status_lookup(INVOICE_STATUS_PAID) context['INVOICE_STATUS_IN_PROGRESS'] = invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS) return context
def test_ap_invoice_edit_permissions(self): self.client.force_login(self.ap_user) self.invoice.status = invoice_status_lookup(INVOICE_STATUS_APPROVED) self.invoice.save() res = self.client.post( reverse('taxpayer-invoice-update', kwargs={ 'taxpayer_id': self.taxpayer.id, 'pk': self.invoice.id }), self.invoice_post_data, ) self.assertEqual(res.status_code, HTTPStatus.FOUND) self.invoice.refresh_from_db() self.assertEqual(self.invoice.invoice_number, self.invoice_post_data['invoice_number'])
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['taxpayer'] = TaxPayer.objects.get(id=self.kwargs['taxpayer_id']) context['INVOICE_STATUS_APPROVED'] = invoice_status_lookup(INVOICE_STATUS_APPROVED) context['INVOICE_STATUS_PENDING'] = invoice_status_lookup(INVOICE_STATUS_PENDING) context['INVOICE_STATUS_CHANGES_REQUEST'] = invoice_status_lookup(INVOICE_STATUS_CHANGES_REQUEST) context['INVOICE_STATUS_REJECTED'] = invoice_status_lookup(INVOICE_STATUS_REJECTED) context['INVOICE_STATUS_PAID'] = invoice_status_lookup(INVOICE_STATUS_PAID) context['INVOICE_STATUS_IN_PROGRESS'] = invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS) context['date_format'] = DATE_FORMAT return context
def test_supplier_invalid_invoice_edit_request(self): self.client.force_login(self.user) self.invoice.status = invoice_status_lookup( INVOICE_STATUS_CHANGES_REQUEST) self.invoice.save() old_invoice_number = self.invoice.invoice_number res = self.client.post( reverse('taxpayer-invoice-update', kwargs={ 'taxpayer_id': self.taxpayer.id, 'pk': self.invoice.id }), {}) self.assertEqual(res.status_code, HTTPStatus.OK) self.invoice.refresh_from_db() self.assertEqual(self.invoice.invoice_number, old_invoice_number) self.assertContains(res, 'This field is required.')
def test_supplier_invoice_edit_permissions(self): self.client.force_login(self.user) self.invoice.status = invoice_status_lookup( INVOICE_STATUS_CHANGES_REQUEST) self.invoice.save() res = self.client.post( reverse('taxpayer-invoice-update', kwargs={ 'taxpayer_id': self.taxpayer.id, 'pk': self.invoice.id }), self.invoice_post_data, follow=True, ) self.assertIn((reverse('invoices-list'), 302), res.redirect_chain) self.assertEqual(res.status_code, HTTPStatus.OK)
def test_generate_a_comment_when_invoice_changes_his_state( self, new_status, _): # Given an invoice and a logged AP # invoice : self.invoice self.client.force_login(self.ap_user) old_status = self.invoice.get_status_display() # When AP changes its state response = self.client.post( reverse('change-invoice-status', kwargs={ 'pk': self.invoice.id, }), {'status': invoice_status_lookup(new_status)}) # Then the invoice should have a comment associated to it with its message comment = invoice_history_comments(self.invoice)[0] self.assertEqual( comment.message, 'Changed: \n{} from {} to {}\n'.format('Status', old_status, new_status)) self.assertEqual(comment.user, self.ap_user) self.assertEqual(HTTPStatus.FOUND, response.status_code)
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['filter_to_xls'] = urllib.parse.urlparse(self.request.get_raw_uri()).query context['is_AP'] = self.request.user.is_AP context['INVOICE_STATUS_APPROVED'] = invoice_status_lookup(INVOICE_STATUS_APPROVED) context['INVOICE_STATUS_PENDING'] = invoice_status_lookup(INVOICE_STATUS_PENDING) context['INVOICE_STATUS_CHANGES_REQUEST'] = invoice_status_lookup(INVOICE_STATUS_CHANGES_REQUEST) context['INVOICE_STATUS_REJECTED'] = invoice_status_lookup(INVOICE_STATUS_REJECTED) context['INVOICE_STATUS_PAID'] = invoice_status_lookup(INVOICE_STATUS_PAID) context['INVOICE_STATUS_IN_PROGRESS'] = invoice_status_lookup(INVOICE_STATUS_IN_PROGRESS) context['date_format'] = DATE_FORMAT all_taxpayers = self.get_taxpayers() context['all_taxpayers'] = all_taxpayers if not self.request.user.is_AP: context['has_approved_taxpayer'] = any(taxpayer.taxpayer_state == 'APPROVED' for taxpayer in all_taxpayers) return context
def test_invoice_status_lookup(self, expected_value, tag): self.assertEqual(invoice_status_lookup(tag), expected_value)
class Invoice(models.Model): class Meta: unique_together = ('taxpayer', 'invoice_number',) taxpayer = models.ForeignKey(TaxPayer, on_delete=models.PROTECT) currency = models.CharField(max_length=200, choices=CURRENCIES, verbose_name=_('Currency')) status = models.CharField( max_length=40, choices=INVOICE_STATUS, default=invoice_status_lookup(INVOICE_STATUS_PENDING), verbose_name=_('Status') ) po_number = models.CharField(max_length=200, help_text="ex: 12341234", verbose_name=_('PO number')) invoice_date = models.DateField(verbose_name=_('Invoice date')) invoice_due_date = models.DateField(verbose_name=_('Due Date')) invoice_date_received = models.DateTimeField(auto_now_add=True, verbose_name=_('Date Received')) invoice_number = models.CharField(max_length=20, verbose_name=_('Invoice Number')) net_amount = models.DecimalField( verbose_name=_('Net amount'), max_digits=20, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))], blank=True, null=True, ) vat = models.DecimalField( max_digits=20, decimal_places=2, validators=[MinValueValidator(Decimal('0.00'))], verbose_name=_('Tax Liens'), blank=True, null=True, ) total_amount = models.DecimalField( max_digits=20, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))], verbose_name=_('Total'), ) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE ) invoice_file = models.FileField( upload_to='file', verbose_name=_('Invoice File'), validators=[ FileExtensionValidator(allowed_extensions=['pdf']), FileSizeValidator(limit_size=INVOICE_MAX_SIZE_FILE), ] ) workday_id = models.CharField(max_length=50, blank=True, null=True) invoice_eb_entity = models.ForeignKey(EBEntity, default=None) new_comment_from_supplier = models.BooleanField(default=False) new_comment_from_ap = models.BooleanField(default=False) history = HistoricalRecords() @property def taxpayer_name(self): return self.taxpayer.business_name
def form_valid(self, form): form.instance.status = invoice_status_lookup(INVOICE_STATUS_PENDING) return super().form_valid(form)