diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml
new file mode 100644
index 00000000..abb5182a
--- /dev/null
+++ b/.github/workflows/django.yml
@@ -0,0 +1,29 @@
+name: Django CI
+
+on:
+ push:
+ branches: [ "master", "development"]
+ pull_request:
+ branches: [ "master", "development" ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Build Docker Image
+ run: docker-compose build web
+
+ - name: Run Tests in Docker
+ run: |
+ docker-compose run --service-ports web coverage run -m pytest --cov=koalixcrm --cov-branch --cov-report xml:test_report/coverage.xml --cov-report term
+ bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r test_report/coverage.xml
+ env:
+ CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
+ - name: Upload Coverage Report
+ uses: actions/upload-artifact@v2
+ with:
+ name: coverage-report
+ path: test_results/coverage.xml
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 06de9139..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-language: python
-python:
-- '3.6'
-
-env:
-- MOZ_HEADLESS=1
-addons:
- firefox: latest
-
-before_install:
- - wget https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux64.tar.gz
- - mkdir geckodriver
- - tar -xzf geckodriver*.tar.gz -C geckodriver
- - export PATH=$PATH:$PWD/geckodriver
-
-install:
- - python setup.py install
- - pip install -r requirements/heroku_requirements.txt
-
-script:
- - pytest --cov=koalixcrm --cov-branch --cov-report xml --cov-report term -m "not version_increase"
- - python-codacy-coverage -r coverage.xml
- - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then pytest -m version_increase; fi
-
-# Deployment
-deploy:
- provider: heroku
- api_key:
- secure: $HEROKU_API_KEY
-
- app: koalix-crm
- on:
- repo: scaphilo/koalixcrm
- run:
- - "python manage.py collectstatic --settings=projectsettings.settings.heroku_settings --noinput"
- - "python manage.py migrate --settings=projectsettings.settings.heroku_settings"
diff --git a/LICENSE b/LICENSE
index f5aebbdd..b4cdf93d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
BSD 3-Clause License
-Copyright (c) 2009-2018, Aaron Riedener, Untereggen, Switzerland
+Copyright (c) 2009-2024, Aaron Riedener, Untereggen, Switzerland
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index 7d36855c..eb2ec696 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@
## Quality badges on master
| Project build: | Codacy results: |Docker: | Social Networks: |
| --- | --- | --- | --- |
-| tbd | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cfae578b5c174f438786c935fa425002)](https://app.codacy.com/gh/KoalixSwitzerland/koalixcrm/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)| [![Docker Automated build](https://img.shields.io/docker/automated/koalixswitzerland/koalixcrm.svg)]()
[![Docker Stars](https://img.shields.io/docker/stars/koalixswitzerland/koalixcrm.svg)]() [![Docker Pulls](https://img.shields.io/docker/pulls/koalixswitzerland/koalixcrm.svg)]() | [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/koalix-crm/Lobby) |
+| [![Django CI](https://github.com/KoalixSwitzerland/koalixcrm/actions/workflows/django.yml/badge.svg)](https://github.com/KoalixSwitzerland/koalixcrm/actions/workflows/django.yml) | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cfae578b5c174f438786c935fa425002)](https://app.codacy.com/gh/KoalixSwitzerland/koalixcrm/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/cfae578b5c174f438786c935fa425002)](https://app.codacy.com/gh/KoalixSwitzerland/koalixcrm/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage)| [![Docker Automated build](https://img.shields.io/docker/automated/koalixswitzerland/koalixcrm.svg)]()
[![Docker Stars](https://img.shields.io/docker/stars/koalixswitzerland/koalixcrm.svg)]() [![Docker Pulls](https://img.shields.io/docker/pulls/koalixswitzerland/koalixcrm.svg)]() | [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/koalix-crm/Lobby) |
## Demos
[demo](http://koalixcrmdemoenglish.koalix.org/admin/).
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 7f7e7e4b..165d4d37 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,14 +1,10 @@
-version: '2.0'
+version: '3.8'
services:
- db:
- image: postgres
- koalixcrm:
- build: .
- environment:
- - DJANGO_SETTINGS_MODULE=projectsettings.settings.docker_development_settings
- - JAVA_HOME=/usr/bin/jdk1.8.0_181/jre
+ web:
+ image: ghcr.io/koalixswitzerland/koalixcrm-dev-container:main
ports:
- "8000:8000"
- depends_on:
- - db
\ No newline at end of file
+ volumes:
+ - .:/usr/src/app
+ - ./data:/usr/src/app/data
\ No newline at end of file
diff --git a/entrypoint.prod.sh b/entrypoint.prod.sh
deleted file mode 100644
index b4880754..00000000
--- a/entrypoint.prod.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-python manage.py migrate --settings=projectsettings.settings.docker_production_settings
-python manage.py runserver 0.0.0.0:8000 --settings=projectsettings.settings.docker_production_settings
\ No newline at end of file
diff --git a/entrypoint.sh b/entrypoint.sh
deleted file mode 100644
index fcc9d566..00000000
--- a/entrypoint.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-python manage.py migrate --settings=projectsettings.settings.docker_development_settings
-python manage.py runserver 0.0.0.0:8000 --settings=projectsettings.settings.docker_development_settings
\ No newline at end of file
diff --git a/koalixcrm/accounting/accounting/account.py b/koalixcrm/accounting/accounting/account.py
index ebc30c0e..7f65d9d3 100644
--- a/koalixcrm/accounting/accounting/account.py
+++ b/koalixcrm/accounting/accounting/account.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django import forms
from koalixcrm.accounting.const.accountTypeChoices import *
@@ -10,6 +10,7 @@
class Account(models.Model):
+ id = models.BigAutoField(primary_key=True)
account_number = models.IntegerField(verbose_name=_("Account Number"))
title = models.CharField(verbose_name=_("Account Title"),
max_length=50)
diff --git a/koalixcrm/accounting/accounting/accounting_period.py b/koalixcrm/accounting/accounting/accounting_period.py
index 8f6dbeee..dd19b9cf 100644
--- a/koalixcrm/accounting/accounting/accounting_period.py
+++ b/koalixcrm/accounting/accounting/accounting_period.py
@@ -3,7 +3,7 @@
from datetime import *
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django import forms
from koalixcrm.accounting.models import Account
from koalixcrm.crm.documents.pdf_export import PDFExport
@@ -16,6 +16,7 @@ class AccountingPeriod(models.Model):
"""Accounting period represents the equivalent of the business logic element of a fiscal year
the accounting period is referred in the booking and is used as a supporting object to generate
balance sheets and profit/loss statements"""
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=200, verbose_name=_("Title")) # For example "Year 2009", "1st Quarter 2009"
begin = models.DateField(verbose_name=_("Begin"))
end = models.DateField(verbose_name=_("End"))
diff --git a/koalixcrm/accounting/accounting/booking.py b/koalixcrm/accounting/accounting/booking.py
index a23a4906..16fa9275 100644
--- a/koalixcrm/accounting/accounting/booking.py
+++ b/koalixcrm/accounting/accounting/booking.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class Booking(models.Model):
+ id = models.BigAutoField(primary_key=True)
from_account = models.ForeignKey('Account', on_delete=models.CASCADE, verbose_name=_("From Account"), related_name="db_booking_fromaccount")
to_account = models.ForeignKey('Account', on_delete=models.CASCADE, verbose_name=_("To Account"), related_name="db_booking_toaccount")
amount = models.DecimalField(max_digits=20, decimal_places=2, verbose_name=_("Amount"))
diff --git a/koalixcrm/accounting/accounting/product_category.py b/koalixcrm/accounting/accounting/product_category.py
index d044d0a5..62396231 100644
--- a/koalixcrm/accounting/accounting/product_category.py
+++ b/koalixcrm/accounting/accounting/product_category.py
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.accounting.models import Account
class ProductCategory(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Product Category Title"),
max_length=50)
profit_account = models.ForeignKey(Account,
diff --git a/koalixcrm/accounting/const/accountTypeChoices.py b/koalixcrm/accounting/const/accountTypeChoices.py
index 5f8e1e5e..8a636e6a 100644
--- a/koalixcrm/accounting/const/accountTypeChoices.py
+++ b/koalixcrm/accounting/const/accountTypeChoices.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
ACCOUNTTYPECHOICES = (
('E', _('Earnings')),
diff --git a/koalixcrm/accounting/migrations/0011_auto_20240329_2207.py b/koalixcrm/accounting/migrations/0011_auto_20240329_2207.py
new file mode 100644
index 00000000..b2b9ccd4
--- /dev/null
+++ b/koalixcrm/accounting/migrations/0011_auto_20240329_2207.py
@@ -0,0 +1,33 @@
+# Generated by Django 3.2.20 on 2024-03-29 22:07
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('accounting', '0010_auto_20181216_2224'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='account',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='accountingperiod',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='booking',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='productcategory',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ ]
diff --git a/koalixcrm/accounting/views.py b/koalixcrm/accounting/views.py
index d05c0adb..2747072d 100644
--- a/koalixcrm/accounting/views.py
+++ b/koalixcrm/accounting/views.py
@@ -6,7 +6,7 @@
from django.http import HttpResponseRedirect
from koalixcrm.crm.exceptions import *
from koalixcrm.djangoUserExtension.exceptions import *
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
def export_pdf(calling_model_admin, request, whereToCreateFrom, whatToCreate, redirectTo):
diff --git a/koalixcrm/crm/const/country.py b/koalixcrm/crm/const/country.py
index 1639198e..28138025 100644
--- a/koalixcrm/crm/const/country.py
+++ b/koalixcrm/crm/const/country.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
COUNTRIES = (
('AF', 'AFG', '004', _('Afghanistan')),
diff --git a/koalixcrm/crm/const/postaladdressprefix.py b/koalixcrm/crm/const/postaladdressprefix.py
index 894c2988..06ee13c3 100644
--- a/koalixcrm/crm/const/postaladdressprefix.py
+++ b/koalixcrm/crm/const/postaladdressprefix.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
POSTALADDRESSPREFIX = (
('F', _('Company')),
diff --git a/koalixcrm/crm/const/purpose.py b/koalixcrm/crm/const/purpose.py
index b1976882..812d0547 100644
--- a/koalixcrm/crm/const/purpose.py
+++ b/koalixcrm/crm/const/purpose.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
PURPOSESADDRESSINCONTRACT = (
('D', _('Delivery Address')),
diff --git a/koalixcrm/crm/const/status.py b/koalixcrm/crm/const/status.py
index 435923d0..354189f0 100644
--- a/koalixcrm/crm/const/status.py
+++ b/koalixcrm/crm/const/status.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
INVOICESTATUS = (
('P', _('Payed')),
diff --git a/koalixcrm/crm/contact/call.py b/koalixcrm/crm/contact/call.py
index b9cf0c77..40ac0bbb 100644
--- a/koalixcrm/crm/contact/call.py
+++ b/koalixcrm/crm/contact/call.py
@@ -3,12 +3,13 @@
from datetime import *
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.utils import timezone
from koalixcrm.crm.const.status import *
class Call(models.Model):
+ id = models.BigAutoField(primary_key=True)
staff = models.ForeignKey('auth.User',
on_delete=models.CASCADE,
limit_choices_to={'is_staff': True},
diff --git a/koalixcrm/crm/contact/contact.py b/koalixcrm/crm/contact/contact.py
index 217f9973..9206b355 100644
--- a/koalixcrm/crm/contact/contact.py
+++ b/koalixcrm/crm/contact/contact.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.contact.phone_address import PhoneAddress
from koalixcrm.crm.contact.email_address import EmailAddress
from koalixcrm.crm.contact.postal_address import PostalAddress
@@ -13,6 +13,7 @@
class Contact(models.Model):
+ id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=300,
verbose_name=_("Name"))
date_of_creation = models.DateTimeField(verbose_name=_("Created at"),
@@ -128,6 +129,7 @@ class ContactEmailAddress(admin.TabularInline):
class ContactPersonAssociation(models.Model):
+ id = models.BigAutoField(primary_key=True)
contact = models.ForeignKey(Contact, on_delete=models.CASCADE, related_name='person_association', blank=True, null=True)
person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='contact_association', blank=True, null=True)
diff --git a/koalixcrm/crm/contact/customer.py b/koalixcrm/crm/contact/customer.py
index 8ca3fc8e..6338f434 100644
--- a/koalixcrm/crm/contact/customer.py
+++ b/koalixcrm/crm/contact/customer.py
@@ -3,7 +3,7 @@
from django.http import HttpResponseRedirect
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.plugin import *
from koalixcrm.crm.contact.contact import Contact, ContactCall, ContactVisit,\
PeopleInlineAdmin, PostalAddressForContact, ContactPostalAddress, \
diff --git a/koalixcrm/crm/contact/customer_billing_cycle.py b/koalixcrm/crm/contact/customer_billing_cycle.py
index 9e325401..67c9572c 100644
--- a/koalixcrm/crm/contact/customer_billing_cycle.py
+++ b/koalixcrm/crm/contact/customer_billing_cycle.py
@@ -2,10 +2,11 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class CustomerBillingCycle(models.Model):
+ id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=300,
verbose_name=_("Name"))
time_to_payment_date = models.IntegerField(verbose_name=_("Days To Payment Date"))
diff --git a/koalixcrm/crm/contact/customer_group.py b/koalixcrm/crm/contact/customer_group.py
index be25ed91..9f63ee85 100644
--- a/koalixcrm/crm/contact/customer_group.py
+++ b/koalixcrm/crm/contact/customer_group.py
@@ -2,10 +2,11 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class CustomerGroup(models.Model):
+ id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=300)
def __str__(self):
diff --git a/koalixcrm/crm/contact/email_address.py b/koalixcrm/crm/contact/email_address.py
index 132e8fd7..e4c18676 100644
--- a/koalixcrm/crm/contact/email_address.py
+++ b/koalixcrm/crm/contact/email_address.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class EmailAddress(models.Model):
+ id = models.BigAutoField(primary_key=True)
email = models.EmailField(max_length=200,
verbose_name=_("Email Address"))
diff --git a/koalixcrm/crm/contact/person.py b/koalixcrm/crm/contact/person.py
index d095e191..00bda320 100644
--- a/koalixcrm/crm/contact/person.py
+++ b/koalixcrm/crm/contact/person.py
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.const.postaladdressprefix import *
class Person(models.Model):
+ id = models.BigAutoField(primary_key=True)
prefix = models.CharField(max_length=1,
choices=POSTALADDRESSPREFIX,
verbose_name=_("Prefix"),
diff --git a/koalixcrm/crm/contact/phone_address.py b/koalixcrm/crm/contact/phone_address.py
index aeec2330..ad989a59 100644
--- a/koalixcrm/crm/contact/phone_address.py
+++ b/koalixcrm/crm/contact/phone_address.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class PhoneAddress(models.Model):
+ id = models.BigAutoField(primary_key=True)
phone = models.CharField(max_length=20,
verbose_name=_("Phone Number"))
diff --git a/koalixcrm/crm/contact/postal_address.py b/koalixcrm/crm/contact/postal_address.py
index 8c5ffdda..83bb9c93 100644
--- a/koalixcrm/crm/contact/postal_address.py
+++ b/koalixcrm/crm/contact/postal_address.py
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.const.country import *
from koalixcrm.crm.const.postaladdressprefix import *
class PostalAddress(models.Model):
+ id = models.BigAutoField(primary_key=True)
prefix = models.CharField(max_length=1,
choices=POSTALADDRESSPREFIX,
verbose_name=_("Prefix"), blank=True,
diff --git a/koalixcrm/crm/contact/supplier.py b/koalixcrm/crm/contact/supplier.py
index fdbf809b..dfec8f31 100644
--- a/koalixcrm/crm/contact/supplier.py
+++ b/koalixcrm/crm/contact/supplier.py
@@ -2,7 +2,7 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.contact.contact import Contact
from koalixcrm.crm.contact.contact import ContactPostalAddress
from koalixcrm.crm.contact.contact import ContactPhoneAddress
diff --git a/koalixcrm/crm/documents/contract.py b/koalixcrm/crm/documents/contract.py
index 2084b66b..a3b62f38 100644
--- a/koalixcrm/crm/documents/contract.py
+++ b/koalixcrm/crm/documents/contract.py
@@ -2,7 +2,7 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.plugin import *
from koalixcrm.crm.contact.phone_address import PhoneAddress
@@ -111,6 +111,7 @@ class ContractEmailAddress(admin.TabularInline):
class Contract(models.Model):
+ id = models.BigAutoField(primary_key=True)
staff = models.ForeignKey('auth.User',
on_delete=models.CASCADE,
limit_choices_to={'is_staff': True},
diff --git a/koalixcrm/crm/documents/delivery_note.py b/koalixcrm/crm/documents/delivery_note.py
index a95609f5..c43f3d7a 100644
--- a/koalixcrm/crm/documents/delivery_note.py
+++ b/koalixcrm/crm/documents/delivery_note.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.const.status import *
from koalixcrm.crm.documents.sales_document import SalesDocument, OptionSalesDocument
diff --git a/koalixcrm/crm/documents/invoice.py b/koalixcrm/crm/documents/invoice.py
index e12eb3a2..5f9db8ca 100644
--- a/koalixcrm/crm/documents/invoice.py
+++ b/koalixcrm/crm/documents/invoice.py
@@ -5,7 +5,7 @@
from django.db import models
from django.contrib import admin
from django.http import HttpResponseRedirect
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.utils.html import format_html
from django.contrib.admin import helpers
from django.shortcuts import render
@@ -120,13 +120,13 @@ def register_invoice_in_accounting(self, request, queryset):
for obj in queryset:
obj.register_invoice_in_accounting(request)
self.message_user(request, _("Successfully registered Invoice in the Accounting"))
- return;
+ return
except OpenInterestAccountMissing as e:
self.message_user(request, "Did not register Invoice in Accounting: " + e.__str__(), level=messages.ERROR)
- return;
+ return
except IncompleteInvoice as e:
self.message_user(request, "Did not register Invoice in Accounting: " + e.__str__(), level=messages.ERROR)
- return;
+ return
register_invoice_in_accounting.short_description = _("Register Invoice in Accounting")
diff --git a/koalixcrm/crm/documents/payment_reminder.py b/koalixcrm/crm/documents/payment_reminder.py
index 57502f82..b05a4692 100644
--- a/koalixcrm/crm/documents/payment_reminder.py
+++ b/koalixcrm/crm/documents/payment_reminder.py
@@ -2,7 +2,7 @@
from datetime import *
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.const.status import *
from django.core.validators import MaxValueValidator, MinValueValidator
from koalixcrm.crm.documents.sales_document import SalesDocument, OptionSalesDocument
diff --git a/koalixcrm/crm/documents/purchase_confirmation.py b/koalixcrm/crm/documents/purchase_confirmation.py
index ad2a44e6..4bf47bf5 100644
--- a/koalixcrm/crm/documents/purchase_confirmation.py
+++ b/koalixcrm/crm/documents/purchase_confirmation.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.documents.sales_document import SalesDocument, OptionSalesDocument
diff --git a/koalixcrm/crm/documents/purchase_order.py b/koalixcrm/crm/documents/purchase_order.py
index ccc9ba17..10c799fc 100644
--- a/koalixcrm/crm/documents/purchase_order.py
+++ b/koalixcrm/crm/documents/purchase_order.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.const.status import *
from koalixcrm.crm.documents.sales_document import SalesDocument, OptionSalesDocument
from koalixcrm.plugin import *
diff --git a/koalixcrm/crm/documents/quote.py b/koalixcrm/crm/documents/quote.py
index e702e063..98b2c4e1 100644
--- a/koalixcrm/crm/documents/quote.py
+++ b/koalixcrm/crm/documents/quote.py
@@ -3,7 +3,7 @@
from datetime import *
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.utils.html import format_html
from koalixcrm.crm.const.status import *
from koalixcrm.plugin import *
diff --git a/koalixcrm/crm/documents/sales_document.py b/koalixcrm/crm/documents/sales_document.py
index b1d35100..fee3a40b 100644
--- a/koalixcrm/crm/documents/sales_document.py
+++ b/koalixcrm/crm/documents/sales_document.py
@@ -3,7 +3,7 @@
from datetime import *
from django.db import models
from django.contrib import admin, messages
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.const.purpose import *
from koalixcrm.global_support_functions import xstr, make_date_utc
from koalixcrm.crm.contact.phone_address import PhoneAddress
@@ -18,6 +18,7 @@
class TextParagraphInSalesDocument(models.Model):
+ id = models.BigAutoField(primary_key=True)
sales_document = models.ForeignKey("SalesDocument", on_delete=models.CASCADE)
purpose = models.CharField(verbose_name=_("Purpose"), max_length=2, choices=PURPOSESTEXTPARAGRAPHINDOCUMENTS)
text_paragraph = models.TextField(verbose_name=_("Text"), blank=False, null=False)
@@ -39,6 +40,7 @@ def __str__(self):
class SalesDocument(models.Model):
+ id = models.BigAutoField(primary_key=True)
contract = models.ForeignKey("Contract",
on_delete=models.CASCADE,
verbose_name=_('Contract'))
diff --git a/koalixcrm/crm/documents/sales_document_position.py b/koalixcrm/crm/documents/sales_document_position.py
index eff84977..bd1f28b0 100644
--- a/koalixcrm/crm/documents/sales_document_position.py
+++ b/koalixcrm/crm/documents/sales_document_position.py
@@ -3,10 +3,11 @@
from django.db import models
from django.contrib import admin
from django.core.validators import MinValueValidator
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class Position(models.Model):
+ id = models.BigAutoField(primary_key=True)
position_number = models.PositiveIntegerField(verbose_name=_("Position Number"),
validators=[MinValueValidator(1)])
quantity = models.DecimalField(verbose_name=_("Quantity"),
diff --git a/koalixcrm/crm/management/commands/koalixcrm_install_defaulttemplates.py b/koalixcrm/crm/management/commands/koalixcrm_install_defaulttemplates.py
index eba26673..55210419 100644
--- a/koalixcrm/crm/management/commands/koalixcrm_install_defaulttemplates.py
+++ b/koalixcrm/crm/management/commands/koalixcrm_install_defaulttemplates.py
@@ -7,7 +7,7 @@
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from filebrowser.base import FileObject
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.conf import settings
DEFAULT_FILE = 'dashboard.py'
diff --git a/koalixcrm/crm/migrations/0015_auto_20180111_2043.py b/koalixcrm/crm/migrations/0015_auto_20180111_2043.py
index 186d9394..ca4de1ae 100644
--- a/koalixcrm/crm/migrations/0015_auto_20180111_2043.py
+++ b/koalixcrm/crm/migrations/0015_auto_20180111_2043.py
@@ -39,11 +39,11 @@ def state_forwards(self, app_label, state):
old_remote_model = '%s.%s' % ("crm", "salescontract")
new_remote_model = '%s.%s' % ("crm", "SalesDocument")
to_reload = []
- for (model_app_label, model_name), model_state in state.models.items():
+ for (model_app_label, model_name), model_state in list(state.models.items()):
if model_name != "salescontract" and model_name != "salesdocument":
new_model_state = model_state
model_with_new_base = state.models[model_app_label, model_name]
- for index, (name, field) in enumerate(model_state.fields):
+ for index, (name, field) in enumerate(model_state.fields.items()):
changed_field = None
remote_field = field.remote_field
if remote_field:
@@ -65,7 +65,7 @@ def state_forwards(self, app_label, state):
changed_field.remote_field.through = new_remote_model
if changed_field:
new_model_state = model_state.clone()
- new_model_state.fields[index] = name, changed_field
+ new_model_state.fields[name] = changed_field
model_changed = True
if old_remote_model in model_state.bases:
new_bases = []
diff --git a/koalixcrm/crm/migrations/0018_auto_20180111_2031.py b/koalixcrm/crm/migrations/0018_auto_20180111_2031.py
index 95890680..a783ad10 100644
--- a/koalixcrm/crm/migrations/0018_auto_20180111_2031.py
+++ b/koalixcrm/crm/migrations/0018_auto_20180111_2031.py
@@ -6,7 +6,7 @@
class Migration(migrations.Migration):
- atomic = False
+ atomic = True
dependencies = [
('crm', '0017_auto_20180111_2022'),
@@ -18,20 +18,25 @@ class Migration(migrations.Migration):
options={'verbose_name': 'Text Paragraph In Sales Document', 'verbose_name_plural': 'Text Paragraphs In Sales Documents'},
),
migrations.RenameField(
- model_name='deliverynote',
+ model_name='quote',
old_name='salescontract_ptr',
new_name='salesdocument_ptr',
),
migrations.RenameField(
- model_name='emailaddressforsalesdocument',
- old_name='contract',
- new_name='sales_document',
+ model_name='invoice',
+ old_name='salescontract_ptr',
+ new_name='salesdocument_ptr',
),
migrations.RenameField(
- model_name='invoice',
+ model_name='deliverynote',
old_name='salescontract_ptr',
new_name='salesdocument_ptr',
),
+ migrations.RenameField(
+ model_name='emailaddressforsalesdocument',
+ old_name='contract',
+ new_name='sales_document',
+ ),
migrations.RenameField(
model_name='paymentreminder',
old_name='salescontract_ptr',
@@ -47,16 +52,6 @@ class Migration(migrations.Migration):
old_name='contract',
new_name='sales_document',
),
- migrations.RenameField(
- model_name='purchaseconfirmation',
- old_name='salescontract_ptr',
- new_name='salesdocument_ptr',
- ),
- migrations.RenameField(
- model_name='quote',
- old_name='salescontract_ptr',
- new_name='salesdocument_ptr',
- ),
migrations.RenameField(
model_name='salesdocumentposition',
old_name='contract',
@@ -67,4 +62,9 @@ class Migration(migrations.Migration):
old_name='sales_contract',
new_name='sales_document',
),
+ migrations.RenameField(
+ model_name='purchaseconfirmation',
+ old_name='salescontract_ptr',
+ new_name='salesdocument_ptr',
+ ),
]
diff --git a/koalixcrm/crm/migrations/0059_auto_20240329_2207.py b/koalixcrm/crm/migrations/0059_auto_20240329_2207.py
new file mode 100644
index 00000000..b6cbe32a
--- /dev/null
+++ b/koalixcrm/crm/migrations/0059_auto_20240329_2207.py
@@ -0,0 +1,228 @@
+# Generated by Django 3.2.20 on 2024-03-29 22:07
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('crm', '0058_auto_20190401_2009'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='agreement',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='agreementstatus',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='agreementtype',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='call',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='contact',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='contactpersonassociation',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='contract',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='currency',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='currencytransform',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='customerbillingcycle',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='customergroup',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='customergrouptransform',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='emailaddress',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='estimation',
+ name='date_until',
+ field=models.DateField(verbose_name='Estimation Until'),
+ ),
+ migrations.AlterField(
+ model_name='estimation',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='estimationstatus',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='genericprojectlink',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='generictasklink',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='person',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='phoneaddress',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='position',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='postaladdress',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='price',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='product',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='producttype',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='project',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='projectlinktype',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='projectstatus',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='reportingperiod',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='reportingperiodstatus',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='resource',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='resourcemanager',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='resourcetype',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='salesdocument',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='task',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='tasklinktype',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='taskstatus',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='tax',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='textparagraphindocumenttemplate',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='textparagraphinsalesdocument',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='unit',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='unittransform',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='work',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ ]
diff --git a/koalixcrm/crm/product/currency.py b/koalixcrm/crm/product/currency.py
index 3d920d9f..e6752792 100644
--- a/koalixcrm/crm/product/currency.py
+++ b/koalixcrm/crm/product/currency.py
@@ -3,10 +3,11 @@
from decimal import Decimal
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class Currency(models.Model):
+ id = models.BigAutoField(primary_key=True)
description = models.CharField(verbose_name=_("Description"),
max_length=100)
short_name = models.CharField(verbose_name=_("Displayed Name After Prices"),
diff --git a/koalixcrm/crm/product/currency_transform.py b/koalixcrm/crm/product/currency_transform.py
index 5d5dbb1b..af9bcb6d 100644
--- a/koalixcrm/crm/product/currency_transform.py
+++ b/koalixcrm/crm/product/currency_transform.py
@@ -2,10 +2,11 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class CurrencyTransform(models.Model):
+ id = models.BigAutoField(primary_key=True)
from_currency = models.ForeignKey('Currency',
on_delete=models.CASCADE,
blank=False,
diff --git a/koalixcrm/crm/product/customer_group_transform.py b/koalixcrm/crm/product/customer_group_transform.py
index c2a19582..381a7b5f 100644
--- a/koalixcrm/crm/product/customer_group_transform.py
+++ b/koalixcrm/crm/product/customer_group_transform.py
@@ -2,10 +2,11 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class CustomerGroupTransform(models.Model):
+ id = models.BigAutoField(primary_key=True)
from_customer_group = models.ForeignKey('CustomerGroup',
on_delete=models.CASCADE,
verbose_name=_("From Customer Group"),
diff --git a/koalixcrm/crm/product/price.py b/koalixcrm/crm/product/price.py
index d86e5415..7270461c 100644
--- a/koalixcrm/crm/product/price.py
+++ b/koalixcrm/crm/product/price.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.product.currency import Currency
from koalixcrm.crm.product.unit import Unit
from koalixcrm.crm.contact.customer_group import CustomerGroup
@@ -11,6 +11,7 @@
class Price(models.Model):
+ id = models.BigAutoField(primary_key=True)
unit = models.ForeignKey(Unit,
on_delete=models.CASCADE,
blank=False,
diff --git a/koalixcrm/crm/product/product.py b/koalixcrm/crm/product/product.py
index 42de3125..97cb1830 100644
--- a/koalixcrm/crm/product/product.py
+++ b/koalixcrm/crm/product/product.py
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class Product(models.Model):
+ id = models.BigAutoField(primary_key=True)
identifier = models.CharField(verbose_name=_("Product Number"),
max_length=200,
null=True,
diff --git a/koalixcrm/crm/product/product_price.py b/koalixcrm/crm/product/product_price.py
index 5e9d5f8c..a7a6bbbc 100644
--- a/koalixcrm/crm/product/product_price.py
+++ b/koalixcrm/crm/product/product_price.py
@@ -2,7 +2,7 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.product.price import Price
diff --git a/koalixcrm/crm/product/product_type.py b/koalixcrm/crm/product/product_type.py
index d9546cdd..827755a5 100644
--- a/koalixcrm/crm/product/product_type.py
+++ b/koalixcrm/crm/product/product_type.py
@@ -2,7 +2,7 @@
from django.contrib import admin
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.product.product_price import ProductPrice
from koalixcrm.crm.product.product_price import ProductPriceInlineAdminView
@@ -12,6 +12,7 @@
class ProductType(models.Model):
+ id = models.BigAutoField(primary_key=True)
description = models.TextField(verbose_name=_("Description"),
null=True,
blank=True)
diff --git a/koalixcrm/crm/product/tax.py b/koalixcrm/crm/product/tax.py
index f48446fa..46be76a0 100644
--- a/koalixcrm/crm/product/tax.py
+++ b/koalixcrm/crm/product/tax.py
@@ -2,10 +2,11 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class Tax(models.Model):
+ id = models.BigAutoField(primary_key=True)
tax_rate = models.DecimalField(max_digits=5,
decimal_places=2,
verbose_name=_("Taxrate in Percentage"))
diff --git a/koalixcrm/crm/product/unit.py b/koalixcrm/crm/product/unit.py
index 6d668990..edea0a54 100644
--- a/koalixcrm/crm/product/unit.py
+++ b/koalixcrm/crm/product/unit.py
@@ -2,10 +2,11 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class Unit(models.Model):
+ id = models.BigAutoField(primary_key=True)
description = models.CharField(verbose_name=_("Description"),
max_length=100)
short_name = models.CharField(verbose_name=_("Displayed Name After Quantity In The Position"),
diff --git a/koalixcrm/crm/product/unit_transform.py b/koalixcrm/crm/product/unit_transform.py
index a134acc0..39816e41 100644
--- a/koalixcrm/crm/product/unit_transform.py
+++ b/koalixcrm/crm/product/unit_transform.py
@@ -2,10 +2,11 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class UnitTransform(models.Model):
+ id = models.BigAutoField(primary_key=True)
from_unit = models.ForeignKey('Unit',
on_delete=models.CASCADE,
verbose_name=_("From Unit"),
diff --git a/koalixcrm/crm/reporting/agreement.py b/koalixcrm/crm/reporting/agreement.py
index 97c29686..bf649b78 100644
--- a/koalixcrm/crm/reporting/agreement.py
+++ b/koalixcrm/crm/reporting/agreement.py
@@ -2,12 +2,13 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.reporting.resource_price import ResourcePrice
class Agreement(models.Model):
"""The Agreement describes the contract between the steer-co or the customer with the project manager"""
+ id = models.BigAutoField(primary_key=True)
task = models.ForeignKey("Task",
on_delete=models.CASCADE,
verbose_name=_('Task'),
diff --git a/koalixcrm/crm/reporting/agreement_status.py b/koalixcrm/crm/reporting/agreement_status.py
index f22262ad..85111d11 100644
--- a/koalixcrm/crm/reporting/agreement_status.py
+++ b/koalixcrm/crm/reporting/agreement_status.py
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
from rest_framework import serializers
class AgreementStatus(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=250,
blank=False,
diff --git a/koalixcrm/crm/reporting/agreement_type.py b/koalixcrm/crm/reporting/agreement_type.py
index 9bab7926..70747913 100644
--- a/koalixcrm/crm/reporting/agreement_type.py
+++ b/koalixcrm/crm/reporting/agreement_type.py
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
class AgreementType(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"), max_length=300, blank=False, null=False)
description = models.TextField(verbose_name=_("Text"), blank=True, null=True)
diff --git a/koalixcrm/crm/reporting/estimation.py b/koalixcrm/crm/reporting/estimation.py
index aede8793..d935ab82 100644
--- a/koalixcrm/crm/reporting/estimation.py
+++ b/koalixcrm/crm/reporting/estimation.py
@@ -2,7 +2,7 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.reporting.resource_price import ResourcePrice
from decimal import *
from django.core.exceptions import ValidationError
@@ -14,7 +14,7 @@ class Estimation(models.Model):
"""The estimation describes the estimated amount of resources which is still required to finish a task
the estimation is done within a reporting period that is not yet closed. The estimation is done only considering
all effective efforts that was reported in the previous and closed reporting periods"""
-
+ id = models.BigAutoField(primary_key=True)
task = models.ForeignKey("Task",
on_delete=models.CASCADE,
verbose_name=_('Task'),
diff --git a/koalixcrm/crm/reporting/estimation_status.py b/koalixcrm/crm/reporting/estimation_status.py
index bf5dbc27..905472ef 100644
--- a/koalixcrm/crm/reporting/estimation_status.py
+++ b/koalixcrm/crm/reporting/estimation_status.py
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
from rest_framework import serializers
class EstimationStatus(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=250,
blank=False,
diff --git a/koalixcrm/crm/reporting/generic_project_link.py b/koalixcrm/crm/reporting/generic_project_link.py
index 6732f3a5..865010fb 100644
--- a/koalixcrm/crm/reporting/generic_project_link.py
+++ b/koalixcrm/crm/reporting/generic_project_link.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib import admin
@@ -9,6 +9,7 @@
class GenericProjectLink(models.Model):
+ id = models.BigAutoField(primary_key=True)
project = models.ForeignKey("Project",
on_delete=models.CASCADE,
verbose_name=_('Project'),
@@ -49,7 +50,7 @@ class GenericLinkInlineAdminView(admin.TabularInline):
'last_modified_by')
extra = 0
- def has_add_permission(self, request):
+ def has_add_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
@@ -65,7 +66,7 @@ class InlineGenericProjectLink(GenericTabularInline):
'last_modified_by')
extra = 0
- def has_add_permission(self, request):
+ def has_add_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
diff --git a/koalixcrm/crm/reporting/generic_task_link.py b/koalixcrm/crm/reporting/generic_task_link.py
index 11e31b78..3806273f 100644
--- a/koalixcrm/crm/reporting/generic_task_link.py
+++ b/koalixcrm/crm/reporting/generic_task_link.py
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib import admin
class GenericTaskLink(models.Model):
+ id = models.BigAutoField(primary_key=True)
task = models.ForeignKey("Task",
on_delete=models.CASCADE,
verbose_name=_('Task'),
@@ -48,7 +49,7 @@ class InlineGenericTaskLink(admin.TabularInline):
'last_modified_by')
extra = 0
- def has_add_permission(self, request):
+ def has_add_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
diff --git a/koalixcrm/crm/reporting/human_resource.py b/koalixcrm/crm/reporting/human_resource.py
index 58cb9649..3dddbe5b 100644
--- a/koalixcrm/crm/reporting/human_resource.py
+++ b/koalixcrm/crm/reporting/human_resource.py
@@ -4,7 +4,7 @@
from dateutil.relativedelta import *
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.djangoUserExtension.user_extension.user_extension import UserExtension
from koalixcrm.crm.reporting.resource import Resource
from koalixcrm.crm.reporting.resource_price import ResourcePriceInlineAdminView
diff --git a/koalixcrm/crm/reporting/project.py b/koalixcrm/crm/reporting/project.py
index 07c76e0e..dbbc9bde 100644
--- a/koalixcrm/crm/reporting/project.py
+++ b/koalixcrm/crm/reporting/project.py
@@ -6,7 +6,7 @@
from django.conf import settings
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.utils.html import format_html
from koalixcrm.crm.reporting.generic_project_link import GenericLinkInlineAdminView
from koalixcrm.crm.reporting.reporting_period import ReportingPeriodInlineAdminView, ReportingPeriod
@@ -20,6 +20,7 @@
class Project(models.Model):
+ id = models.BigAutoField(primary_key=True)
project_manager = models.ForeignKey('auth.User', on_delete=models.CASCADE, limit_choices_to={'is_staff': True},
verbose_name=_("Staff"),
related_name="db_rel_project_staff",
diff --git a/koalixcrm/crm/reporting/project_link_type.py b/koalixcrm/crm/reporting/project_link_type.py
index 470eceae..c3765c59 100644
--- a/koalixcrm/crm/reporting/project_link_type.py
+++ b/koalixcrm/crm/reporting/project_link_type.py
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
class ProjectLinkType(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"), max_length=300, blank=False, null=False)
description = models.TextField(verbose_name=_("Text"), blank=True, null=True)
diff --git a/koalixcrm/crm/reporting/project_status.py b/koalixcrm/crm/reporting/project_status.py
index ccebbc49..a576a108 100644
--- a/koalixcrm/crm/reporting/project_status.py
+++ b/koalixcrm/crm/reporting/project_status.py
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
from rest_framework import serializers
class ProjectStatus(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=250,
blank=False,
diff --git a/koalixcrm/crm/reporting/reporting_period.py b/koalixcrm/crm/reporting/reporting_period.py
index 887c4610..aaa3bc65 100644
--- a/koalixcrm/crm/reporting/reporting_period.py
+++ b/koalixcrm/crm/reporting/reporting_period.py
@@ -3,7 +3,7 @@
from datetime import *
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.documents.pdf_export import PDFExport
from koalixcrm.crm.exceptions import ReportingPeriodNotFound
from koalixcrm.crm.reporting.work import WorkInlineAdminView
@@ -15,6 +15,7 @@
class ReportingPeriod(models.Model):
"""The reporting period is referred in the work, in the expenses and purchase orders, it is used as a
supporting object to generate project reports"""
+ id = models.BigAutoField(primary_key=True)
project = models.ForeignKey("Project",
on_delete=models.CASCADE,
verbose_name=_("Project"),
@@ -267,7 +268,7 @@ class ReportingPeriodInlineAdminView(admin.TabularInline):
}),
)
- def has_add_permission(self, request):
+ def has_add_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
diff --git a/koalixcrm/crm/reporting/reporting_period_status.py b/koalixcrm/crm/reporting/reporting_period_status.py
index ae9594cc..553ec1b9 100644
--- a/koalixcrm/crm/reporting/reporting_period_status.py
+++ b/koalixcrm/crm/reporting/reporting_period_status.py
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
from rest_framework import serializers
class ReportingPeriodStatus(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=250,
blank=False,
diff --git a/koalixcrm/crm/reporting/resource.py b/koalixcrm/crm/reporting/resource.py
index d5420b94..e77f2152 100644
--- a/koalixcrm/crm/reporting/resource.py
+++ b/koalixcrm/crm/reporting/resource.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class Resource(models.Model):
+ id = models.BigAutoField(primary_key=True)
resource_manager = models.ForeignKey("ResourceManager",
on_delete=models.CASCADE,
verbose_name=_("Manager"),
diff --git a/koalixcrm/crm/reporting/resource_manager.py b/koalixcrm/crm/reporting/resource_manager.py
index 77f62bc7..0c753682 100644
--- a/koalixcrm/crm/reporting/resource_manager.py
+++ b/koalixcrm/crm/reporting/resource_manager.py
@@ -3,10 +3,11 @@
from django.db import models
from django.contrib import admin
from koalixcrm.djangoUserExtension.user_extension.user_extension import UserExtension
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
class ResourceManager(models.Model):
+ id = models.BigAutoField(primary_key=True)
user = models.ForeignKey(UserExtension,
on_delete=models.CASCADE,
verbose_name=_("User"))
diff --git a/koalixcrm/crm/reporting/resource_price.py b/koalixcrm/crm/reporting/resource_price.py
index bb7d7564..c3e50101 100644
--- a/koalixcrm/crm/reporting/resource_price.py
+++ b/koalixcrm/crm/reporting/resource_price.py
@@ -2,7 +2,7 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.product.price import Price
from koalixcrm.crm.reporting.resource import Resource
diff --git a/koalixcrm/crm/reporting/resource_type.py b/koalixcrm/crm/reporting/resource_type.py
index 5bc109e0..5c8c0c88 100644
--- a/koalixcrm/crm/reporting/resource_type.py
+++ b/koalixcrm/crm/reporting/resource_type.py
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
class ResourceType(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=300,
blank=False,
diff --git a/koalixcrm/crm/reporting/task.py b/koalixcrm/crm/reporting/task.py
index 06cadae4..f578f826 100644
--- a/koalixcrm/crm/reporting/task.py
+++ b/koalixcrm/crm/reporting/task.py
@@ -2,7 +2,7 @@
from decimal import *
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
from django.utils.html import format_html
from koalixcrm.crm.reporting.agreement import Agreement
@@ -21,6 +21,7 @@
class Task(models.Model):
""" The Task model"""
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=100,
blank=True,
@@ -622,7 +623,7 @@ class TaskInlineAdminView(admin.TabularInline):
)
extra = 1
- def has_add_permission(self, request):
+ def has_add_permission(self, request, obj=None):
return True
def has_delete_permission(self, request, obj=None):
diff --git a/koalixcrm/crm/reporting/task_link_type.py b/koalixcrm/crm/reporting/task_link_type.py
index 4277a711..4ede555b 100644
--- a/koalixcrm/crm/reporting/task_link_type.py
+++ b/koalixcrm/crm/reporting/task_link_type.py
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
class TaskLinkType(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"), max_length=300, blank=False, null=False)
description = models.TextField(verbose_name=_("Text"), blank=True, null=True)
diff --git a/koalixcrm/crm/reporting/task_status.py b/koalixcrm/crm/reporting/task_status.py
index 078f0db5..fd12505f 100644
--- a/koalixcrm/crm/reporting/task_status.py
+++ b/koalixcrm/crm/reporting/task_status.py
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import admin
from rest_framework import serializers
class TaskStatus(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"), max_length=250, blank=False, null=False)
description = models.TextField(verbose_name=_("Text"), blank=True, null=True)
is_done = models.BooleanField(verbose_name=_("Status represents task done"),)
diff --git a/koalixcrm/crm/reporting/work.py b/koalixcrm/crm/reporting/work.py
index fd9b0296..72704ccc 100644
--- a/koalixcrm/crm/reporting/work.py
+++ b/koalixcrm/crm/reporting/work.py
@@ -4,7 +4,7 @@
from django.forms import ValidationError
from django.contrib import admin
from django.utils.html import format_html
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.documents.pdf_export import PDFExport
from koalixcrm.global_support_functions import *
from koalixcrm.crm.exceptions import ReportingPeriodDoneDeleteNotPossible
@@ -12,6 +12,7 @@
class Work(models.Model):
+ id = models.BigAutoField(primary_key=True)
human_resource = models.ForeignKey("HumanResource", on_delete=models.CASCADE)
date = models.DateField(verbose_name=_("Date"),
blank=False,
diff --git a/koalixcrm/crm/tests/test_create_sales_document_from_contract.py b/koalixcrm/crm/tests/test_create_sales_document_from_contract.py
index 8ed75d24..c20bc2c6 100644
--- a/koalixcrm/crm/tests/test_create_sales_document_from_contract.py
+++ b/koalixcrm/crm/tests/test_create_sales_document_from_contract.py
@@ -1,47 +1,32 @@
# -*- coding: utf-8 -*-
import pytest
import os
-from django.contrib.staticfiles.testing import StaticLiveServerTestCase
-from selenium import webdriver
-from koalixcrm.test_support_functions import *
+from koalixcrm.test.test_support_functions import *
from koalixcrm.crm.factories.factory_contract import StandardContractFactory
from koalixcrm.crm.factories.factory_user import AdminUserFactory
from koalixcrm.crm.factories.factory_customer_group import StandardCustomerGroupFactory
from koalixcrm.djangoUserExtension.factories.factory_document_template import StandardQuoteTemplateFactory
from koalixcrm.djangoUserExtension.factories.factory_document_template import StandardInvoiceTemplateFactory
from koalixcrm.djangoUserExtension.factories.factory_document_template import StandardPurchaseOrderTemplateFactory
+from koalixcrm.test.UITests import UITests
from koalixcrm.crm.documents.quote import Quote
from koalixcrm.crm.documents.invoice import Invoice
from koalixcrm.crm.documents.purchase_order import PurchaseOrder
-class CreateSalesDocumentFromContract(StaticLiveServerTestCase):
- @classmethod
- def setUpClass(cls):
- super(CreateSalesDocumentFromContract, cls).setUpClass()
- firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- cls.selenium = webdriver.Firefox(firefox_options=firefox_options)
- cls.selenium.implicitly_wait(10)
- cls.test_user = AdminUserFactory.create()
- cls.test_customer_group = StandardCustomerGroupFactory.create()
- cls.test_contract = StandardContractFactory.create()
- cls.test_quote_template = StandardQuoteTemplateFactory.create()
- cls.test_invoice_template = StandardInvoiceTemplateFactory.create()
- cls.test_purchase_order_template = StandardPurchaseOrderTemplateFactory.create()
+class CreateSalesDocumentFromContract(UITests):
- @classmethod
- def tearDownClass(cls):
- cls.selenium.quit()
- super(CreateSalesDocumentFromContract, cls).tearDownClass()
+ def setUp(self):
+ super().setUp()
+ self.test_user = AdminUserFactory.create()
+ self.test_customer_group = StandardCustomerGroupFactory.create()
+ self.test_contract = StandardContractFactory.create()
+ self.test_quote_template = StandardQuoteTemplateFactory.create()
+ self.test_invoice_template = StandardInvoiceTemplateFactory.create()
+ self.test_purchase_order_template = StandardPurchaseOrderTemplateFactory.create()
def tearDown(self):
- if len(self._outcome.errors) > 0:
- directory = os.getcwd() + "/test_results/Screenshots/"
- if not os.path.exists(directory):
- os.makedirs(directory)
- self.selenium.save_screenshot(directory + "%s.png" % "test_name")
- super(CreateSalesDocumentFromContract, self).tearDown()
+ super().tearDown()
@pytest.mark.front_end_tests
def test_create_sales_document_from_contract(self):
@@ -55,9 +40,9 @@ def test_create_sales_document_from_contract(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
diff --git a/koalixcrm/crm/tests/test_create_sales_document_from_invoice.py b/koalixcrm/crm/tests/test_create_sales_document_from_invoice.py
index c15c6059..26e7c3d7 100644
--- a/koalixcrm/crm/tests/test_create_sales_document_from_invoice.py
+++ b/koalixcrm/crm/tests/test_create_sales_document_from_invoice.py
@@ -3,7 +3,7 @@
import os
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium import webdriver
-from koalixcrm.test_support_functions import *
+from koalixcrm.test.test_support_functions import *
from koalixcrm.crm.factories.factory_contract import StandardContractFactory
from koalixcrm.crm.factories.factory_invoice import StandardInvoiceFactory
from koalixcrm.crm.factories.factory_user import AdminUserFactory
@@ -26,8 +26,8 @@ class CreateSalesDocumentFromContract(StaticLiveServerTestCase):
def setUpClass(cls):
super(CreateSalesDocumentFromContract, cls).setUpClass()
firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- cls.selenium = webdriver.Firefox(firefox_options=firefox_options)
+ firefox_options.add_argument("--headless")
+ cls.selenium = webdriver.Firefox(options=firefox_options)
cls.selenium.implicitly_wait(10)
cls.test_user = AdminUserFactory.create()
cls.test_customer_group = StandardCustomerGroupFactory.create()
@@ -64,9 +64,9 @@ def test_create_sales_document_from_quote(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
diff --git a/koalixcrm/crm/tests/test_create_sales_document_from_quote.py b/koalixcrm/crm/tests/test_create_sales_document_from_quote.py
index eb489969..59d78081 100644
--- a/koalixcrm/crm/tests/test_create_sales_document_from_quote.py
+++ b/koalixcrm/crm/tests/test_create_sales_document_from_quote.py
@@ -3,7 +3,7 @@
import os
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium import webdriver
-from koalixcrm.test_support_functions import *
+from koalixcrm.test.test_support_functions import *
from koalixcrm.crm.factories.factory_contract import StandardContractFactory
from koalixcrm.crm.factories.factory_quote import StandardQuoteFactory
from koalixcrm.crm.factories.factory_user import AdminUserFactory
@@ -22,8 +22,8 @@ class CreateSalesDocumentFromContract(StaticLiveServerTestCase):
def setUpClass(cls):
super(CreateSalesDocumentFromContract, cls).setUpClass()
firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- cls.selenium = webdriver.Firefox(firefox_options=firefox_options)
+ firefox_options.add_argument("--headless")
+ cls.selenium = webdriver.Firefox(options=firefox_options)
cls.selenium.implicitly_wait(10)
cls.test_user = AdminUserFactory.create()
cls.test_customer_group = StandardCustomerGroupFactory.create()
@@ -58,9 +58,9 @@ def test_create_sales_document_from_quote(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
diff --git a/koalixcrm/crm/tests/test_delete_of_empty_row.py b/koalixcrm/crm/tests/test_delete_of_empty_row.py
index f49106e8..1c64c701 100644
--- a/koalixcrm/crm/tests/test_delete_of_empty_row.py
+++ b/koalixcrm/crm/tests/test_delete_of_empty_row.py
@@ -1,15 +1,7 @@
# -*- coding: utf-8 -*-
import pytest
-import time
import datetime
-from django.contrib.staticfiles.testing import StaticLiveServerTestCase
-from selenium import webdriver
-from selenium.common.exceptions import TimeoutException
-from selenium.webdriver.support.ui import WebDriverWait
-from selenium.webdriver.support import expected_conditions
-from selenium.webdriver.common.by import By
-from selenium.webdriver.common.keys import Keys
-from koalixcrm.test_support_functions import *
+from koalixcrm.test.test_support_functions import *
from koalixcrm.crm.factories.factory_user import AdminUserFactory
from koalixcrm.crm.factories.factory_customer import StandardCustomerFactory
from koalixcrm.crm.factories.factory_customer_group import StandardCustomerGroupFactory
@@ -18,105 +10,104 @@
from koalixcrm.crm.factories.factory_reporting_period import StandardReportingPeriodFactory
from koalixcrm.crm.factories.factory_task import StandardTaskFactory
from koalixcrm.crm.reporting.work import Work
+from koalixcrm.test.UITests import UITests
+from selenium.webdriver.support import expected_conditions
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.keys import Keys
from koalixcrm.crm.factories.factory_human_resource import StandardHumanResourceFactory
-class TimeTrackingWorkEntry(StaticLiveServerTestCase):
- @classmethod
- def setUpClass(cls):
- super(TimeTrackingWorkEntry, cls).setUpClass()
- firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- cls.selenium = webdriver.Firefox(firefox_options=firefox_options)
- cls.selenium.implicitly_wait(10)
- cls.test_user = AdminUserFactory.create()
- cls.test_customer_group = StandardCustomerGroupFactory.create()
- cls.test_customer = StandardCustomerFactory.create(is_member_of=(cls.test_customer_group,))
- cls.test_user_extension = StandardUserExtensionFactory.create(user=cls.test_user)
- cls.test_human_resource = StandardHumanResourceFactory.create(user=cls.test_user_extension)
- cls.test_currency = StandardCurrencyFactory.create()
- cls.test_reporting_period = StandardReportingPeriodFactory.create()
- cls.test_1st_task = StandardTaskFactory.create(title="1st Test Task",
- project=cls.test_reporting_period.project,
- )
+class TimeTrackingWorkEntry(UITests):
+
+ def setUp(self):
+ super().setUp()
+ self.test_user = AdminUserFactory.create()
+ self.test_customer_group = StandardCustomerGroupFactory.create()
+ self.test_customer = StandardCustomerFactory.create(is_member_of=(self.test_customer_group,))
+ self.test_user_extension = StandardUserExtensionFactory.create(user=self.test_user)
+ self.test_human_resource = StandardHumanResourceFactory.create(user=self.test_user_extension)
+ self.test_currency = StandardCurrencyFactory.create()
+ self.test_reporting_period = StandardReportingPeriodFactory.create()
+ self.test_1st_task = StandardTaskFactory.create(
+ title="1st Test Task",
+ project=self.test_reporting_period.project,)
- @classmethod
- def tearDownClass(cls):
- cls.selenium.quit()
- super(TimeTrackingWorkEntry, cls).tearDownClass()
+ def tearDown(self):
+ super().tearDown()
@pytest.mark.front_end_tests
def test_delete_of_new_blank_row(self):
- selenium = self.selenium
# login
- selenium.get('%s%s' % (self.live_server_url, '/koalixcrm/crm/reporting/time_tracking/'))
+ self.selenium.get('%s%s' % (self.live_server_url, '/koalixcrm/crm/reporting/time_tracking/'))
# the browser will be redirected to the login page
timeout = 5
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_username'))
- WebDriverWait(selenium, timeout).until(element_present)
+ WebDriverWait(self.selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = self.selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = self.selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = self.selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
- # after the login, the browser is redirected to the target url /koalixcrm/crm/reporting/time_tracking
+ time.sleep(5)
+ self.selenium.get('%s%s' % (self.live_server_url, '/koalixcrm/crm/reporting/time_tracking/'))
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_form-0-project'))
- WebDriverWait(selenium, timeout).until(element_present)
+ WebDriverWait(self.selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
# find the form element
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-project"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-task"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_0]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_0"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_1]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_1"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-worked_hours"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-description"]')
- assert_when_element_does_not_exist(self, 'save')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-project"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-task"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_0"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_0"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_1"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_1"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-worked_hours"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-description"]')
+ fail_when_element_does_not_exist(self, '//*[@name="save"]')
# check existence of a second form before pressing add more
- assert_when_element_exists(self, '//*[@id="id_form-1-project"]')
- add_more_button = selenium.find_element_by_xpath('//*[@id="add_more"]')
+ fail_when_element_exists(self, '//*[@id="id_form-1-project"]')
+ add_more_button = self.selenium.find_element('xpath', '//*[@id="add_more"]')
add_more_button.send_keys(Keys.RETURN)
time.sleep(1)
# check existence of a second form after pressing add more
- assert_when_element_does_not_exist(self, '//*[@id="id_form-1-project"]')
- add_more_button = selenium.find_element_by_xpath('//*[@id="add_more"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-1-project"]')
+ add_more_button = self.selenium.find_element('xpath', '//*[@id="add_more"]')
add_more_button.send_keys(Keys.RETURN)
- delete_form = selenium.find_element_by_id('id_form-1-DELETE')
- if not delete_form.is_selected():
- delete_form.send_keys(Keys.SPACE)
+ delete_form = expected_conditions.presence_of_element_located((By.ID, 'id_form-1-DELETE'))
+ delete_checkbox = self.selenium.find_element(By.ID, 'id_form-1-DELETE')
+ if not delete_checkbox.is_selected():
+ delete_checkbox.send_keys(Keys.SPACE)
# check existence of a second form after pressing add more
- assert_when_element_does_not_exist(self, '//*[@id="id_form-2-project"]')
- project = selenium.find_element_by_xpath('//*[@id="id_form-2-project"]')
- datetime_start_date = selenium.find_element_by_xpath('//*[@id="id_form-2-datetime_start_0"]')
- datetime_start_time = selenium.find_element_by_xpath('//*[@id="id_form-2-datetime_start_1"]')
- datetime_stop_date = selenium.find_element_by_xpath('//*[@id="id_form-2-datetime_stop_0"]')
- datetime_stop_time = selenium.find_element_by_xpath('//*[@id="id_form-2-datetime_stop_1"]')
- description = selenium.find_element_by_xpath('//*[@id="id_form-2-description"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-2-project"]')
+ project = self.selenium.find_element('xpath', '//*[@id="id_form-2-project"]')
+ datetime_start_date = self.selenium.find_element('xpath', '//*[@id="id_form-2-datetime_start_0"]')
+ datetime_start_time = self.selenium.find_element('xpath', '//*[@id="id_form-2-datetime_start_1"]')
+ datetime_stop_date = self.selenium.find_element('xpath', '//*[@id="id_form-2-datetime_stop_0"]')
+ datetime_stop_time = self.selenium.find_element('xpath', '//*[@id="id_form-2-datetime_stop_1"]')
+ description = self.selenium.find_element('xpath', '//*[@id="id_form-2-description"]')
project.send_keys(self.test_reporting_period.project.id.__str__())
datetime_start_date.send_keys(datetime.date.today().__str__())
datetime_stop_date.send_keys(datetime.date.today().__str__())
datetime_start_time.send_keys(datetime.time(11, 55).__str__())
datetime_stop_time.send_keys(datetime.time(12, 55).__str__())
description.send_keys("This is a test work entered through the front-end")
- task = selenium.find_element_by_xpath('//*[@id="id_form-2-task"]/option[text()="'+self.test_1st_task.title+'"]')
+ task = self.selenium.find_element('xpath', '//*[@id="id_form-2-task"]/option[text()="'+self.test_1st_task.title+'"]')
task.click()
- save_button = selenium.find_element_by_name('save')
+ save_button = self.selenium.find_element('xpath', '//*[@name="save"]')
save_button.send_keys(Keys.RETURN)
time.sleep(1)
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_form-1-project'))
- WebDriverWait(selenium, timeout).until(element_present)
+ WebDriverWait(self.selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- assert_when_element_does_not_exist(self, '//*[@id="id_form-1-task"]')
- assert_when_element_exists(self, '//*[@id="id_form-2-task"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-1-task"]')
+ fail_when_element_exists(self, '//*[@id="id_form-2-task"]')
work = Work.objects.get(description="This is a test work entered through the front-end")
self.assertEqual(type(work), Work)
work.delete()
diff --git a/koalixcrm/crm/tests/test_poject_admin_view.py b/koalixcrm/crm/tests/test_project_admin_view.py
similarity index 67%
rename from koalixcrm/crm/tests/test_poject_admin_view.py
rename to koalixcrm/crm/tests/test_project_admin_view.py
index 749422e2..c6bfa37f 100644
--- a/koalixcrm/crm/tests/test_poject_admin_view.py
+++ b/koalixcrm/crm/tests/test_project_admin_view.py
@@ -1,25 +1,20 @@
# -*- coding: utf-8 -*-
import pytest
-from django.test import LiveServerTestCase
-from selenium import webdriver
-from selenium.common.exceptions import TimeoutException
-from selenium.webdriver.support.ui import WebDriverWait
+from koalixcrm.test.test_support_functions import *
+from koalixcrm.crm.factories.factory_user import AdminUserFactory
+from koalixcrm.test.UITests import UITests
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.by import By
-from selenium.webdriver.common.keys import Keys
-from koalixcrm.crm.factories.factory_user import AdminUserFactory
-class TestProjectAdminView(LiveServerTestCase):
+class TestProjectAdminView(UITests):
def setUp(self):
- firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- self.selenium = webdriver.Firefox(firefox_options=firefox_options)
+ super().setUp()
self.test_user = AdminUserFactory.create()
def tearDown(self):
- self.selenium.quit()
+ super().tearDown()
@pytest.mark.front_end_tests
def test_project_admin(self):
@@ -27,18 +22,19 @@ def test_project_admin(self):
# login
selenium.get('%s%s' % (self.live_server_url, '/admin/crm/project/'))
# the browser will be redirected to the login page
- timeout = 5
+ timeout = 10
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_username'))
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
- submit_button.send_keys(Keys.RETURN)
+ time.sleep(5)
+ self.selenium.get('%s%s' % (self.live_server_url, '/admin/crm/project/'))
try:
element_present = expected_conditions.presence_of_element_located((By.ID,
'/html/body/div/article/header/ul/li/a'))
@@ -49,7 +45,7 @@ def test_project_admin(self):
selenium.get('%s%s' % (self.live_server_url, '/admin/crm/project/add'))
try:
- element_present = expected_conditions.presence_of_element_located((By.ID, '//*[@id="id_project_status"]'))
+ element_present = expected_conditions.presence_of_element_located((By.ID, 'id_project_status'))
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
diff --git a/koalixcrm/crm/tests/test_supplier_admin_view.py b/koalixcrm/crm/tests/test_supplier_admin_view.py
index a55acbe3..7db6cb60 100644
--- a/koalixcrm/crm/tests/test_supplier_admin_view.py
+++ b/koalixcrm/crm/tests/test_supplier_admin_view.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
import pytest
-from django.test import LiveServerTestCase
-from selenium import webdriver
+from koalixcrm.test.test_support_functions import *
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
@@ -9,59 +8,59 @@
from selenium.webdriver.common.keys import Keys
from koalixcrm.crm.factories.factory_user import AdminUserFactory
from koalixcrm.crm.contact.supplier import Supplier
+from koalixcrm.test.UITests import UITests
-class TestSupplierAdminView(LiveServerTestCase):
+class TestSupplierAdminView(UITests):
def setUp(self):
- firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- self.selenium = webdriver.Firefox(firefox_options=firefox_options)
+ super().setUp()
self.test_user = AdminUserFactory.create()
def tearDown(self):
- self.selenium.quit()
+ super().tearDown()
@pytest.mark.front_end_tests
def test_supplier_admin(self):
- selenium = self.selenium
# login
- selenium.get('%s%s' % (self.live_server_url, '/admin/crm/supplier/'))
+ self.selenium.get('%s%s' % (self.live_server_url, '/admin/crm/supplier/'))
# the browser will be redirected to the login page
- timeout = 5
+ timeout = 10
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_username'))
- WebDriverWait(selenium, timeout).until(element_present)
+ WebDriverWait(self.selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = self.selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = self.selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = self.selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
+ time.sleep(5)
+ self.selenium.get('%s%s' % (self.live_server_url, '/admin/crm/supplier/'))
try:
element_present = expected_conditions.presence_of_element_located((By.ID,
'/html/body/div/article/header/ul/li/a'))
- WebDriverWait(selenium, timeout).until(element_present)
+ WebDriverWait(self.selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
# find the form element
- selenium.get('%s%s' % (self.live_server_url, '/admin/crm/supplier/add'))
+ self.selenium.get('%s%s' % (self.live_server_url, '/admin/crm/supplier/add'))
try:
- element_present = expected_conditions.presence_of_element_located((By.ID, '//*[@id="id_name"]'))
- WebDriverWait(selenium, timeout).until(element_present)
+ element_present = expected_conditions.presence_of_element_located((By.ID, 'id_name'))
+ WebDriverWait(self.selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- name = selenium.find_element_by_xpath('//*[@id="id_name"]')
+ name = self.selenium.find_element('xpath', '//*[@id="id_name"]')
name.send_keys("This is the name of a supplier")
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/form/div/footer/ul/li[1]/input')
+ submit_button = self.selenium.find_element('xpath', '/html/body/div/article/div/form/div/footer/ul/li[1]/input')
submit_button.send_keys(Keys.RETURN)
try:
element_present = expected_conditions.presence_of_element_located((By.ID,
'/html/body/div/article/header/ul/li/a'))
- WebDriverWait(selenium, timeout).until(element_present)
+ WebDriverWait(self.selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
supplier = Supplier.objects.get(name="This is the name of a supplier")
diff --git a/koalixcrm/crm/tests/test_time_tracking_add_row.py b/koalixcrm/crm/tests/test_time_tracking_add_row.py
index ad65bc19..d934fea6 100644
--- a/koalixcrm/crm/tests/test_time_tracking_add_row.py
+++ b/koalixcrm/crm/tests/test_time_tracking_add_row.py
@@ -1,21 +1,18 @@
import pytest
-from django.test import LiveServerTestCase
-from selenium import webdriver
-from koalixcrm.test_support_functions import *
+from koalixcrm.test.test_support_functions import *
from koalixcrm.crm.factories.factory_user import AdminUserFactory
from koalixcrm.crm.factories.factory_customer import StandardCustomerFactory
from koalixcrm.crm.factories.factory_customer_group import StandardCustomerGroupFactory
from koalixcrm.crm.factories.factory_currency import StandardCurrencyFactory
from koalixcrm.crm.factories.factory_human_resource import StandardHumanResourceFactory
from koalixcrm.djangoUserExtension.factories.factory_user_extension import StandardUserExtensionFactory
+from koalixcrm.test.UITests import UITests
-class TimeTrackingAddRow(LiveServerTestCase):
+class TimeTrackingAddRow(UITests):
def setUp(self):
- firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- self.selenium = webdriver.Firefox(firefox_options=firefox_options)
+ super().setUp()
self.test_user = AdminUserFactory.create()
self.test_customer_group = StandardCustomerGroupFactory.create()
self.test_customer = StandardCustomerFactory.create(is_member_of=(self.test_customer_group,))
@@ -24,7 +21,7 @@ def setUp(self):
self.test_human_resource = StandardHumanResourceFactory.create(user=self.test_user_extension)
def tearDown(self):
- self.selenium.quit()
+ super().tearDown()
@pytest.mark.front_end_tests
def test_add_new_row(self):
@@ -38,12 +35,14 @@ def test_add_new_row(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
+ time.sleep(5)
+ selenium.get('%s%s' % (self.live_server_url, '/koalixcrm/crm/reporting/time_tracking/'))
# after the login, the browser is redirected to the target url /koalixcrm/crm/reporting/time_tracking
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_form-0-project'))
@@ -51,16 +50,18 @@ def test_add_new_row(self):
except TimeoutException:
print("Timed out waiting for page to load")
# find the form element
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-project"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-task"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-date"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-start_time"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-stop_time"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-description"]')
- assert_when_element_does_not_exist(self, 'save')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-project"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-task"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_0"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_1"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_0"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_1"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-worked_hours"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-description"]')
+ fail_when_element_does_not_exist(self, '//*[@name="save"]')
# check existence of a second form before pressing add more
- assert_when_element_exists(self, '//*[@id="id_form-1-project"]')
- add_more_button = selenium.find_element_by_xpath('//*[@id="add_more"]')
+ fail_when_element_exists(self, '//*[@id="id_form-1-project"]')
+ add_more_button = selenium.find_element('xpath', '//*[@id="add_more"]')
add_more_button.send_keys(Keys.RETURN)
# check existence of a second form after pressing add more
- assert_when_element_does_not_exist(self, '//*[@id="id_form-1-project"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-1-project"]')
diff --git a/koalixcrm/crm/tests/test_user_is_not_human_resource.py b/koalixcrm/crm/tests/test_user_is_not_human_resource.py
index ee58f7af..73981278 100644
--- a/koalixcrm/crm/tests/test_user_is_not_human_resource.py
+++ b/koalixcrm/crm/tests/test_user_is_not_human_resource.py
@@ -1,8 +1,7 @@
import pytest
-from django.test import LiveServerTestCase
-from selenium import webdriver
from selenium.webdriver.support.ui import Select
-from koalixcrm.test_support_functions import *
+from koalixcrm.test.test_support_functions import *
+from koalixcrm.test.UITests import UITests
from koalixcrm.crm.factories.factory_user import AdminUserFactory
from koalixcrm.crm.factories.factory_customer import StandardCustomerFactory
from koalixcrm.crm.factories.factory_customer_group import StandardCustomerGroupFactory
@@ -10,12 +9,10 @@
from koalixcrm.djangoUserExtension.factories.factory_user_extension import StandardUserExtensionFactory
-class TimeTrackingAddRow(LiveServerTestCase):
+class TimeTrackingAddRow(UITests):
def setUp(self):
- firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- self.selenium = webdriver.Firefox(firefox_options=firefox_options)
+ super().setUp()
self.test_user = AdminUserFactory.create()
self.test_customer_group = StandardCustomerGroupFactory.create()
self.test_customer = StandardCustomerFactory.create(is_member_of=(self.test_customer_group,))
@@ -23,7 +20,7 @@ def setUp(self):
self.test_user_extension = StandardUserExtensionFactory.create(user=self.test_user)
def tearDown(self):
- self.selenium.quit()
+ super().tearDown()
@pytest.mark.front_end_tests
def test_add_new_row(self):
@@ -37,12 +34,14 @@ def test_add_new_row(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
+ time.sleep(5)
+ selenium.get('%s%s' % (self.live_server_url, '/koalixcrm/crm/reporting/time_tracking/'))
# after the login, the browser is redirected to the target url /koalixcrm/crm/reporting/time_tracking
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_next_steps'))
@@ -55,10 +54,10 @@ def test_add_new_row(self):
# In this test_step it is checked whether the form contains the required fields. the test will then select
# to return to the start page instead of defining a new human resource
- assert_when_element_does_not_exist(self, '//*[@id="id_next_steps"]')
- assert_when_element_does_not_exist(self, 'confirm_selection')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/form/table/tbody/tr[3]/td/input[2]')
- selection = Select(selenium.find_element_by_xpath('//*[@id="id_next_steps"]'))
+ fail_when_element_does_not_exist(self, '//*[@id="id_next_steps"]')
+ fail_when_element_does_not_exist(self, '//*[@name="confirm_selection"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/form/table/tbody/tr[3]/td/input[2]')
+ selection = Select(selenium.find_element('xpath', '//*[@id="id_next_steps"]'))
selection.select_by_value("return_to_start")
submit_button.send_keys(Keys.RETURN)
try:
@@ -79,10 +78,10 @@ def test_add_new_row(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- assert_when_element_does_not_exist(self, '//*[@id="id_next_steps"]')
- assert_when_element_does_not_exist(self, 'confirm_selection')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/form/table/tbody/tr[3]/td/input[2]')
- selection = Select(selenium.find_element_by_xpath('//*[@id="id_next_steps"]'))
+ fail_when_element_does_not_exist(self, '//*[@id="id_next_steps"]')
+ fail_when_element_does_not_exist(self, '//*[@name="confirm_selection"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/form/table/tbody/tr[3]/td/input[2]')
+ selection = Select(selenium.find_element('xpath', '//*[@id="id_next_steps"]'))
selection.select_by_value("create_human_resource")
submit_button.send_keys(Keys.RETURN)
try:
diff --git a/koalixcrm/crm/tests/test_view_work_entry_form.py b/koalixcrm/crm/tests/test_view_work_entry_form.py
index 0a5a08ce..f1eafd43 100644
--- a/koalixcrm/crm/tests/test_view_work_entry_form.py
+++ b/koalixcrm/crm/tests/test_view_work_entry_form.py
@@ -1,15 +1,7 @@
# -*- coding: utf-8 -*-
import pytest
-import time
import datetime
-from django.contrib.staticfiles.testing import StaticLiveServerTestCase
-from selenium import webdriver
-from selenium.common.exceptions import TimeoutException
-from selenium.webdriver.support.ui import WebDriverWait
-from selenium.webdriver.support import expected_conditions
-from selenium.webdriver.common.by import By
-from selenium.webdriver.common.keys import Keys
-from koalixcrm.test_support_functions import *
+from koalixcrm.test.test_support_functions import *
from koalixcrm.crm.factories.factory_user import AdminUserFactory
from koalixcrm.crm.factories.factory_customer import StandardCustomerFactory
from koalixcrm.crm.factories.factory_customer_group import StandardCustomerGroupFactory
@@ -17,37 +9,31 @@
from koalixcrm.djangoUserExtension.factories.factory_user_extension import StandardUserExtensionFactory
from koalixcrm.crm.factories.factory_reporting_period import StandardReportingPeriodFactory
from koalixcrm.crm.factories.factory_task import StandardTaskFactory
+from koalixcrm.test.UITests import UITests
from koalixcrm.crm.reporting.work import Work
from koalixcrm.crm.factories.factory_human_resource import StandardHumanResourceFactory
-class TimeTrackingWorkEntry(StaticLiveServerTestCase):
+class TimeTrackingWorkEntry(UITests):
- @classmethod
- def setUpClass(cls):
- super(TimeTrackingWorkEntry, cls).setUpClass()
- firefox_options = webdriver.firefox.options.Options()
- firefox_options.set_headless(headless=True)
- cls.selenium = webdriver.Firefox(firefox_options=firefox_options)
- cls.selenium.implicitly_wait(10)
- cls.test_user = AdminUserFactory.create()
- cls.test_customer_group = StandardCustomerGroupFactory.create()
- cls.test_customer = StandardCustomerFactory.create(is_member_of=(cls.test_customer_group,))
- cls.test_currency = StandardCurrencyFactory.create()
- cls.test_user_extension = StandardUserExtensionFactory.create(user=cls.test_user)
- cls.test_human_resource = StandardHumanResourceFactory.create(user=cls.test_user_extension)
- cls.test_customer_group = StandardCustomerGroupFactory.create()
- cls.test_customer = StandardCustomerFactory.create(is_member_of=(cls.test_customer_group,))
- cls.test_currency = StandardCurrencyFactory.create()
- cls.test_reporting_period = StandardReportingPeriodFactory.create()
- cls.test_1st_task = StandardTaskFactory.create(title="1st Test Task",
- project=cls.test_reporting_period.project,
- )
+ def setUp(self):
+ super().setUp()
+ self.test_user = AdminUserFactory.create()
+ self.test_customer_group = StandardCustomerGroupFactory.create()
+ self.test_customer = StandardCustomerFactory.create(is_member_of=(self.test_customer_group,))
+ self.test_currency = StandardCurrencyFactory.create()
+ self.test_user_extension = StandardUserExtensionFactory.create(user=self.test_user)
+ self.test_human_resource = StandardHumanResourceFactory.create(user=self.test_user_extension)
+ self.test_customer_group = StandardCustomerGroupFactory.create()
+ self.test_customer = StandardCustomerFactory.create(is_member_of=(self.test_customer_group,))
+ self.test_currency = StandardCurrencyFactory.create()
+ self.test_reporting_period = StandardReportingPeriodFactory.create()
+ self.test_1st_task = StandardTaskFactory.create(
+ title="1st Test Task",
+ project=self.test_reporting_period.project)
- @classmethod
- def tearDownClass(cls):
- cls.selenium.quit()
- super(TimeTrackingWorkEntry, cls).tearDownClass()
+ def tearDown(self):
+ super().tearDown()
@pytest.mark.front_end_tests
def test_registration_of_work(self):
@@ -61,43 +47,44 @@ def test_registration_of_work(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- username = selenium.find_element_by_xpath('//*[@id="id_username"]')
- password = selenium.find_element_by_xpath('//*[@id="id_password"]')
- submit_button = selenium.find_element_by_xpath('/html/body/div/article/div/div/form/div/ul/li/input')
+ username = selenium.find_element('xpath', '//*[@id="id_username"]')
+ password = selenium.find_element('xpath', '//*[@id="id_password"]')
+ submit_button = selenium.find_element('xpath', '/html/body/div/article/div/div/form/div/ul/li/input')
username.send_keys("admin")
password.send_keys("admin")
submit_button.send_keys(Keys.RETURN)
- # after the login, the browser is redirected to the target url /koalixcrm/crm/reporting/time_tracking
+ time.sleep(5)
+ selenium.get('%s%s' % (self.live_server_url, '/koalixcrm/crm/reporting/time_tracking/'))
try:
element_present = expected_conditions.presence_of_element_located((By.ID, 'id_form-0-project'))
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
# find the form element
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-project"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-task"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_0]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_0"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_1]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_1"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-worked_hours"]')
- assert_when_element_does_not_exist(self, '//*[@id="id_form-0-description"]')
- assert_when_element_does_not_exist(self, 'save')
- project = selenium.find_element_by_xpath('//*[@id="id_form-0-project"]')
- datetime_start_date = selenium.find_element_by_xpath('//*[@id="id_form-0-datetime_start_0"]')
- datetime_start_time = selenium.find_element_by_xpath('//*[@id="id_form-0-datetime_start_1"]')
- datetime_stop_date = selenium.find_element_by_xpath('//*[@id="id_form-0-datetime_stop_0"]')
- datetime_stop_time = selenium.find_element_by_xpath('//*[@id="id_form-0-datetime_stop_1"]')
- description = selenium.find_element_by_xpath('//*[@id="id_form-0-description"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-project"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-task"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_0"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_0"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_start_1"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-datetime_stop_1"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-worked_hours"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-0-description"]')
+ fail_when_element_does_not_exist(self, '//*[@name="save"]')
+ project = selenium.find_element('xpath', '//*[@id="id_form-0-project"]')
+ datetime_start_date = selenium.find_element('xpath', '//*[@id="id_form-0-datetime_start_0"]')
+ datetime_start_time = selenium.find_element('xpath', '//*[@id="id_form-0-datetime_start_1"]')
+ datetime_stop_date = selenium.find_element('xpath', '//*[@id="id_form-0-datetime_stop_0"]')
+ datetime_stop_time = selenium.find_element('xpath', '//*[@id="id_form-0-datetime_stop_1"]')
+ description = selenium.find_element('xpath', '//*[@id="id_form-0-description"]')
project.send_keys(self.test_reporting_period.project.id.__str__())
datetime_start_date.send_keys(datetime.date.today().__str__())
datetime_stop_date.send_keys(datetime.date.today().__str__())
datetime_start_time.send_keys(datetime.time(11, 55).__str__())
datetime_stop_time.send_keys(datetime.time(12, 55).__str__())
description.send_keys("This is a test work entered through the front-end")
- task = selenium.find_element_by_xpath('//*[@id="id_form-0-task"]/option[text()="'+self.test_1st_task.title+'"]')
+ task = selenium.find_element('xpath', '//*[@id="id_form-0-task"]/option[text()="'+self.test_1st_task.title+'"]')
task.click()
- save_button = selenium.find_element_by_name('save')
+ save_button = selenium.find_element('name', 'save')
save_button.send_keys(Keys.RETURN)
time.sleep(1)
try:
@@ -105,6 +92,6 @@ def test_registration_of_work(self):
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- assert_when_element_does_not_exist(self, '//*[@id="id_form-1-task"]')
+ fail_when_element_does_not_exist(self, '//*[@id="id_form-1-task"]')
work = Work.objects.get(description="This is a test work entered through the front-end")
self.assertEqual(type(work), Work)
diff --git a/koalixcrm/crm/views/create_task.py b/koalixcrm/crm/views/create_task.py
index 69ffc55c..e1d7679b 100644
--- a/koalixcrm/crm/views/create_task.py
+++ b/koalixcrm/crm/views/create_task.py
@@ -3,7 +3,7 @@
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.core.exceptions import ObjectDoesNotExist
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib.contenttypes.models import ContentType
from koalixcrm.crm.exceptions import *
from koalixcrm.djangoUserExtension.exceptions import *
diff --git a/koalixcrm/crm/views/newdocument.py b/koalixcrm/crm/views/newdocument.py
index 845097ad..f218bb0b 100644
--- a/koalixcrm/crm/views/newdocument.py
+++ b/koalixcrm/crm/views/newdocument.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.http import Http404
from django.http import HttpResponseRedirect
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.contrib import messages
from koalixcrm.crm.exceptions import *
diff --git a/koalixcrm/crm/views/pdfexport.py b/koalixcrm/crm/views/pdfexport.py
index 033ffcd6..001b8caf 100644
--- a/koalixcrm/crm/views/pdfexport.py
+++ b/koalixcrm/crm/views/pdfexport.py
@@ -5,7 +5,7 @@
from django.http import Http404
from django.http import HttpResponse
from django.http import HttpResponseRedirect
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.exceptions import *
from koalixcrm.djangoUserExtension.exceptions import *
from django.contrib import messages
diff --git a/koalixcrm/crm/views/time_tracking.py b/koalixcrm/crm/views/time_tracking.py
index d264c5b7..4c34defc 100644
--- a/koalixcrm/crm/views/time_tracking.py
+++ b/koalixcrm/crm/views/time_tracking.py
@@ -4,7 +4,7 @@
from django.http import HttpResponseRedirect, Http404
from django.contrib import messages
from django.shortcuts import render
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from django.template.context_processors import csrf
from django.contrib.auth.decorators import login_required
from koalixcrm.djangoUserExtension.models import UserExtension
diff --git a/koalixcrm/djangoUserExtension/const/purpose.py b/koalixcrm/djangoUserExtension/const/purpose.py
index cfffbaa5..e315dc31 100644
--- a/koalixcrm/djangoUserExtension/const/purpose.py
+++ b/koalixcrm/djangoUserExtension/const/purpose.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
PURPOSESADDRESSINUSEREXTENTION = (
('H', _('Private')),
diff --git a/koalixcrm/djangoUserExtension/migrations/0008_auto_20240329_2207.py b/koalixcrm/djangoUserExtension/migrations/0008_auto_20240329_2207.py
new file mode 100644
index 00000000..63e69c15
--- /dev/null
+++ b/koalixcrm/djangoUserExtension/migrations/0008_auto_20240329_2207.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.2.20 on 2024-03-29 22:07
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('djangoUserExtension', '0007_auto_20180702_1628'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='documenttemplate',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='templateset',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='userextension',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ ]
diff --git a/koalixcrm/djangoUserExtension/user_extension/document_template.py b/koalixcrm/djangoUserExtension/user_extension/document_template.py
index cf7ceb16..c25bf836 100644
--- a/koalixcrm/djangoUserExtension/user_extension/document_template.py
+++ b/koalixcrm/djangoUserExtension/user_extension/document_template.py
@@ -2,7 +2,7 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from filebrowser.fields import FileBrowseField
@@ -12,6 +12,7 @@
class DocumentTemplate(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=100,
blank=True,
diff --git a/koalixcrm/djangoUserExtension/user_extension/template_set.py b/koalixcrm/djangoUserExtension/user_extension/template_set.py
index da9f1dee..12e9f89c 100644
--- a/koalixcrm/djangoUserExtension/user_extension/template_set.py
+++ b/koalixcrm/djangoUserExtension/user_extension/template_set.py
@@ -2,13 +2,14 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.global_support_functions import xstr
from koalixcrm.crm.exceptions import *
class TemplateSet(models.Model):
+ id = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name=_("Title"),
max_length=100)
invoice_template = models.ForeignKey("InvoiceTemplate",
diff --git a/koalixcrm/djangoUserExtension/user_extension/text_paragraph.py b/koalixcrm/djangoUserExtension/user_extension/text_paragraph.py
index a47bc7b1..5acdd66f 100644
--- a/koalixcrm/djangoUserExtension/user_extension/text_paragraph.py
+++ b/koalixcrm/djangoUserExtension/user_extension/text_paragraph.py
@@ -2,12 +2,13 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.const.purpose import *
class TextParagraphInDocumentTemplate(models.Model):
+ id = models.BigAutoField(primary_key=True)
document_template = models.ForeignKey("djangoUserExtension.DocumentTemplate", on_delete=models.CASCADE)
purpose = models.CharField(verbose_name=_("Purpose"), max_length=2, choices=PURPOSESTEXTPARAGRAPHINDOCUMENTS)
text_paragraph = models.TextField(verbose_name=_("Text"), blank=False, null=False)
diff --git a/koalixcrm/djangoUserExtension/user_extension/user_extension.py b/koalixcrm/djangoUserExtension/user_extension/user_extension.py
index 648221da..c3a9647a 100644
--- a/koalixcrm/djangoUserExtension/user_extension/user_extension.py
+++ b/koalixcrm/djangoUserExtension/user_extension/user_extension.py
@@ -2,7 +2,7 @@
from django.db import models
from django.contrib import admin
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.crm.contact.postal_address import PostalAddress
from koalixcrm.crm.contact.phone_address import PhoneAddress
@@ -13,6 +13,7 @@
class UserExtension(models.Model):
+ id = models.BigAutoField(primary_key=True)
user = models.ForeignKey("auth.User",
on_delete=models.CASCADE,
blank=False,
diff --git a/koalixcrm/subscriptions/admin.py b/koalixcrm/subscriptions/admin.py
index b6895b5b..f2c6eadd 100644
--- a/koalixcrm/subscriptions/admin.py
+++ b/koalixcrm/subscriptions/admin.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.http import HttpResponseRedirect
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from koalixcrm.subscriptions.models import *
diff --git a/koalixcrm/subscriptions/const/events.py b/koalixcrm/subscriptions/const/events.py
index 2b15cfd3..a98fcdde 100644
--- a/koalixcrm/subscriptions/const/events.py
+++ b/koalixcrm/subscriptions/const/events.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
SUBSCRITIONEVENTS = (
('O', _('Offered')),
diff --git a/koalixcrm/subscriptions/migrations/0006_auto_20240329_2207.py b/koalixcrm/subscriptions/migrations/0006_auto_20240329_2207.py
new file mode 100644
index 00000000..8d32a9cc
--- /dev/null
+++ b/koalixcrm/subscriptions/migrations/0006_auto_20240329_2207.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.2.20 on 2024-03-29 22:07
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('subscriptions', '0005_auto_20181013_2228'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='subscription',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='subscriptionevent',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterField(
+ model_name='subscriptiontype',
+ name='id',
+ field=models.BigAutoField(primary_key=True, serialize=False),
+ ),
+ ]
diff --git a/koalixcrm/subscriptions/models.py b/koalixcrm/subscriptions/models.py
index ceb73d3e..3764605f 100644
--- a/koalixcrm/subscriptions/models.py
+++ b/koalixcrm/subscriptions/models.py
@@ -2,13 +2,14 @@
from datetime import *
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
from filebrowser.fields import FileBrowseField
from koalixcrm.subscriptions.const.events import *
import koalixcrm.crm.documents
class Subscription(models.Model):
+ id = models.BigAutoField(primary_key=True)
contract = models.ForeignKey('crm.Contract', on_delete=models.CASCADE, verbose_name=_('Subscription Type'))
subscription_type = models.ForeignKey('SubscriptionType', on_delete=models.CASCADE, verbose_name=_('Subscription Type'), null=True)
@@ -51,6 +52,7 @@ class Meta:
class SubscriptionEvent(models.Model):
+ id = models.BigAutoField(primary_key=True)
subscriptions = models.ForeignKey('Subscription',
on_delete=models.CASCADE,
verbose_name=_('Subscription'))
@@ -69,6 +71,7 @@ class Meta:
class SubscriptionType(models.Model):
+ id = models.BigAutoField(primary_key=True)
product_type = models.ForeignKey('crm.ProductType',
verbose_name=_('Product Type'),
on_delete=models.deletion.SET_NULL,
diff --git a/koalixcrm/test/UITests.py b/koalixcrm/test/UITests.py
new file mode 100644
index 00000000..a10d9904
--- /dev/null
+++ b/koalixcrm/test/UITests.py
@@ -0,0 +1,17 @@
+from django.contrib.staticfiles.testing import StaticLiveServerTestCase
+from selenium import webdriver
+
+
+class UITests(StaticLiveServerTestCase):
+
+ def setUp(self):
+ firefox_options = webdriver.firefox.options.Options()
+ firefox_options.add_argument("--headless")
+ self.selenium = webdriver.Firefox(options=firefox_options)
+ self.selenium.implicitly_wait(10)
+
+ def tearDown(self):
+ if len(self._outcome.errors) > 0:
+ test_method_name = self._testMethodName
+ self.selenium.save_screenshot("test_results/Screenshots/%s.png" % test_method_name)
+ self.selenium.quit()
diff --git a/koalixcrm/test/__init__.py b/koalixcrm/test/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/koalixcrm/test_support_functions.py b/koalixcrm/test/test_support_functions.py
similarity index 71%
rename from koalixcrm/test_support_functions.py
rename to koalixcrm/test/test_support_functions.py
index d4dee05e..b8adaa25 100644
--- a/koalixcrm/test_support_functions.py
+++ b/koalixcrm/test/test_support_functions.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
-
-from selenium.common.exceptions import NoSuchElementException
import time
+from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
@@ -9,23 +8,24 @@
from selenium.webdriver.common.keys import Keys
-def assert_when_element_does_not_exist(testcase, xpath):
+def fail_when_element_does_not_exist(testcase, xpath):
try:
- testcase.selenium.find_element_by_xpath(xpath)
+ testcase.selenium.find_element('xpath', xpath)
except NoSuchElementException:
- testcase.assertTrue(True, xpath+" does not exist")
+ testcase.assertTrue(False, xpath+" should exist but it does not")
+ pass
-def assert_when_element_exists(testcase, xpath):
+def fail_when_element_exists(testcase, xpath):
try:
- testcase.selenium.find_element_by_xpath(xpath)
+ testcase.selenium.find_element('xpath', xpath)
+ testcase.assertTrue(False, xpath+" should not exist but it does")
except NoSuchElementException:
- testcase.assertTrue(True, xpath+" does exist")
-
+ pass
def assert_when_element_is_not_equal_to(testcase, xpath, string):
try:
- element = testcase.selenium.find_element_by_xpath(xpath)
+ element = testcase.selenium.find_element('xpath', xpath)
if element.text != string:
print("issue")
except NoSuchElementException:
@@ -43,18 +43,18 @@ def create_sales_document_from_reference(test_case,
selenium = test_case.selenium
selenium.get('%s%s' % (test_case.live_server_url, '/admin/crm/'+reference_type+'/'))
time.sleep(1)
- assert_when_element_does_not_exist(test_case,
+ fail_when_element_does_not_exist(test_case,
'/html/body/div/article/div/form/section/div/table/tbody/tr/td[1]/input')
- assert_when_element_does_not_exist(test_case, '/html/body/div/article/div/form/footer/ul/li/div/select')
- assert_when_element_does_not_exist(test_case, '/html/body/div/article/div/form/footer/ul/li/div/button')
- contract_1 = selenium.find_element_by_xpath(
+ fail_when_element_does_not_exist(test_case, '/html/body/div/article/div/form/footer/ul/li/div/select')
+ fail_when_element_does_not_exist(test_case, '/html/body/div/article/div/form/footer/ul/li/div/button')
+ contract_1 = selenium.find_element('xpath',
'/html/body/div/article/div/form/section/div/table/tbody/tr/td[1]/input')
if not contract_1.is_selected():
contract_1.send_keys(Keys.SPACE)
- action_create_offer = selenium.find_element_by_xpath(
+ action_create_offer = selenium.find_element('xpath',
'/html/body/div/article/div/form/footer/ul/li/div/select/option[@value="'+action_name+'"]')
action_create_offer.click()
- ok_button = selenium.find_element_by_xpath('/html/body/div/article/div/form/footer/ul/li/div/button')
+ ok_button = selenium.find_element('xpath', '/html/body/div/article/div/form/footer/ul/li/div/button')
ok_button.send_keys(Keys.RETURN)
time.sleep(1)
try:
@@ -62,23 +62,23 @@ def create_sales_document_from_reference(test_case,
WebDriverWait(selenium, timeout).until(element_present)
except TimeoutException:
print("Timed out waiting for page to load")
- assert_when_element_does_not_exist(test_case, '/html/body/div/article/ul/li')
- document_type_template = selenium.find_element_by_xpath(
+ fail_when_element_does_not_exist(test_case, '/html/body/div/article/ul/li')
+ document_type_template = selenium.find_element('xpath',
'//*[@id="id_'+template_name+'"]/option[@value="' +
template_to_select.id.__str__() + '"]')
document_type_template.click()
- save_button = selenium.find_element_by_xpath('/html/body/div/article/div/form/div/footer/ul/li[2]/input')
+ save_button = selenium.find_element('xpath', '/html/body/div/article/div/form/div/footer/ul/li[2]/input')
save_button.send_keys(Keys.RETURN)
time.sleep(1)
selenium.get('%s%s' % (test_case.live_server_url, '/admin/crm/'+reference_type+'/'))
- contract_1 = selenium.find_element_by_xpath(
+ contract_1 = selenium.find_element('xpath',
'/html/body/div/article/div/form/section/div/table/tbody/tr/td[1]/input')
if not contract_1.is_selected():
contract_1.send_keys(Keys.SPACE)
- action_create_sales_document = selenium.find_element_by_xpath(
+ action_create_sales_document = selenium.find_element('xpath',
'/html/body/div/article/div/form/footer/ul/li/div/select/option[@value="'+action_name+'"]')
action_create_sales_document.click()
- ok_button = selenium.find_element_by_xpath('/html/body/div/article/div/form/footer/ul/li/div/button')
+ ok_button = selenium.find_element('xpath', '/html/body/div/article/div/form/footer/ul/li/div/button')
ok_button.send_keys(Keys.RETURN)
time.sleep(1)
try:
diff --git a/koalixcrm/version.py b/koalixcrm/version.py
index 72511189..87fda557 100644
--- a/koalixcrm/version.py
+++ b/koalixcrm/version.py
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
-KOALIXCRM_VERSION = "1.13dev10"
\ No newline at end of file
+KOALIXCRM_VERSION = "1.13.0"
\ No newline at end of file
diff --git a/projectsettings/dashboard.py b/projectsettings/dashboard.py
index 65280aec..ada1d9a2 100644
--- a/projectsettings/dashboard.py
+++ b/projectsettings/dashboard.py
@@ -1,12 +1,12 @@
"""
-This file was generated with the customdashboard management command and
+This file was generated with the custom dashboard management command and
contains the class for the main dashboard.
To activate your index dashboard add the following to your settings.py::
GRAPPELLI_INDEX_DASHBOARD = 'koalixcrm.dashboard.CustomIndexDashboard'
"""
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from grappelli.dashboard import modules, Dashboard
from grappelli.dashboard.utils import get_admin_site_name
from koalixcrm.version import KOALIXCRM_VERSION
diff --git a/projectsettings/settings/base_settings.py b/projectsettings/settings/base_settings.py
index afbc41c9..df5e6191 100644
--- a/projectsettings/settings/base_settings.py
+++ b/projectsettings/settings/base_settings.py
@@ -1,28 +1,11 @@
"""
-Django base settings for test_koalixcrm project.
-
-Generated by 'django-admin startproject' using Django 1.11.3.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.11/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/1.11/ref/settings/
+Django base settings for koalixcrm project.
"""
+
import os
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'modify_during_deployment'
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
-
# Application definition
PREREQUISITE_APPS = [
'django.contrib.contenttypes',
@@ -101,24 +84,12 @@
},
]
-
-# Internationalization
-# https://docs.djangoproject.com/en/1.11/topics/i18n/
-
LANGUAGE_CODE = 'en-us'
-
TIME_ZONE = 'UTC'
-
USE_I18N = True
-
USE_L10N = True
-
USE_TZ = True
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/1.11/howto/static-files/
-
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
diff --git a/projectsettings/settings/development_docker_sqlite_settings.py b/projectsettings/settings/development_docker_sqlite_settings.py
new file mode 100644
index 00000000..32b38466
--- /dev/null
+++ b/projectsettings/settings/development_docker_sqlite_settings.py
@@ -0,0 +1,25 @@
+"""
+Django settings for koalixcrm project when used in development environment.
+"""
+
+from .base_settings import *
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'modify_during_deployment'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = ['*']
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+
+FOP_EXECUTABLE = "/usr/bin/fop-2.9/fop/fop"
+GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
+
+KOALIXCRM_REST_API_AUTH = True
diff --git a/projectsettings/settings/development_settings.py b/projectsettings/settings/development_settings.py
deleted file mode 100644
index c06fed70..00000000
--- a/projectsettings/settings/development_settings.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from .base_settings import *
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-ALLOWED_HOSTS = ['*']
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'NAME': 'postgres',
- 'USER': 'postgres',
- 'HOST': 'db',
- 'PORT': 5432,
- }
-}
-
-FOP_EXECUTABLE = "/usr/bin/fop"
-GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
-
-KOALIXCRM_REST_API_AUTH = False
\ No newline at end of file
diff --git a/projectsettings/settings/development_sqlite_settings.py b/projectsettings/settings/development_sqlite_settings.py
deleted file mode 100644
index 2d4334d1..00000000
--- a/projectsettings/settings/development_sqlite_settings.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from .base_settings import *
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-
-
-ALLOWED_HOSTS = ['*']
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
- }
-}
-
-FOP_EXECUTABLE = "C:/Users/ria/Downloads/fop-2.3/fop/fop.cmd"
-GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
-
-KOALIXCRM_REST_API_AUTH = True
diff --git a/projectsettings/settings/development_sqlite_settings_linux.py b/projectsettings/settings/development_sqlite_settings_linux.py
deleted file mode 100644
index daa99295..00000000
--- a/projectsettings/settings/development_sqlite_settings_linux.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from .base_settings import *
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-
-
-ALLOWED_HOSTS = ['*']
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
- }
-}
-
-FOP_EXECUTABLE = "/usr/bin/fop-2.2/fop/fop"
-GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
-
-KOALIXCRM_REST_API_AUTH = True
diff --git a/projectsettings/settings/docker_development_settings.py b/projectsettings/settings/docker_development_settings.py
deleted file mode 100644
index b7e833b9..00000000
--- a/projectsettings/settings/docker_development_settings.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from .base_settings import *
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-ALLOWED_HOSTS = ['*']
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'NAME': 'postgres',
- 'USER': 'postgres',
- 'HOST': 'db',
- 'PORT': 5432,
- }
-}
-
-FOP_EXECUTABLE = "/usr/bin/fop-2.2/fop/fop"
-GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
-FILEBROWSER_CONVERT_FILENAME = False
-KOALIXCRM_REST_API_AUTH = False
\ No newline at end of file
diff --git a/projectsettings/settings/docker_production_settings.py b/projectsettings/settings/docker_production_settings.py
deleted file mode 100644
index f52d8f70..00000000
--- a/projectsettings/settings/docker_production_settings.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from .base_settings import *
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-
-ALLOWED_HOSTS = ['*']
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'NAME': 'postgres',
- 'USER': 'postgres',
- 'HOST': 'db',
- 'PORT': 5432,
- }
-}
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = False
-
-FOP_EXECUTABLE = "/usr/bin/fop-2.2/fop/fop"
-GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
-FILEBROWSER_CONVERT_FILENAME = False
-KOALIXCRM_REST_API_AUTH = True
\ No newline at end of file
diff --git a/projectsettings/settings/heroku_settings.py b/projectsettings/settings/heroku_settings.py
deleted file mode 100644
index 57cc3463..00000000
--- a/projectsettings/settings/heroku_settings.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""
-Django settings for test_koalixcrm project.
-
-Generated by 'django-admin startproject' using Django 1.11.3.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.11/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/1.11/ref/settings/
-"""
-from .base_settings import *
-
-# Update database configuration with $DATABASE_URL.
-import dj_database_url
-DATABASES = { 'default': dj_database_url.config(conn_max_age=500) }
-FOP_EXECUTABLE = "/usr/bin/fop"
-GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
-ALLOWED_HOSTS = ['koalix-crm.herokuapp.com']
-
-KOALIXCRM_REST_API_AUTH = True
diff --git a/projectsettings/settings/production_docker_postgres_settings.py b/projectsettings/settings/production_docker_postgres_settings.py
new file mode 100644
index 00000000..6c00a291
--- /dev/null
+++ b/projectsettings/settings/production_docker_postgres_settings.py
@@ -0,0 +1,29 @@
+"""
+Django settings for koalixcrm project when used in productive environment.
+"""
+
+from .base_settings import *
+
+SECRET_KEY = os.environ.get("SECRET_KEY")
+
+DEBUG = bool(os.environ.get("DEBUG", default=0))
+
+# 'DJANGO_ALLOWED_HOSTS' should be a single string of hosts with a space between each.
+# For example: 'DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]'
+ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
+
+DATABASES = {
+ "default": {
+ "ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.postgresql"),
+ "NAME": os.environ.get("SQL_DATABASE", BASE_DIR / "postgres"),
+ "USER": os.environ.get("SQL_USER", "postgres"),
+ "PASSWORD": os.environ.get("SQL_PASSWORD", "password"),
+ "HOST": os.environ.get("SQL_HOST", "localhost"),
+ "PORT": os.environ.get("SQL_PORT", "5432"),
+ }
+}
+
+FOP_EXECUTABLE = "/usr/bin/fop-2.2/fop/fop"
+GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
+FILEBROWSER_CONVERT_FILENAME = False
+KOALIXCRM_REST_API_AUTH = True
\ No newline at end of file
diff --git a/projectsettings/settings/production_settings.py b/projectsettings/settings/production_settings.py
deleted file mode 100644
index 220f0430..00000000
--- a/projectsettings/settings/production_settings.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from .base_settings import *
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-
-ALLOWED_HOSTS = ['*']
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'NAME': 'postgres',
- 'USER': 'postgres',
- 'PASSWORD': 'modify_during_deployment',
- 'HOST': 'db',
- 'PORT': 5432,
- }
-}
-
-FOP_EXECUTABLE = "/usr/bin/fop"
-GRAPPELLI_INDEX_DASHBOARD = 'projectsettings.dashboard.CustomIndexDashboard'
-KOALIXCRM_REST_API_AUTH = True
\ No newline at end of file
diff --git a/pytest.ini b/pytest.ini
index deb0774e..d456662d 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,2 +1,6 @@
[pytest]
-DJANGO_SETTINGS_MODULE=projectsettings.settings.development_sqlite_settings_linux
+DJANGO_SETTINGS_MODULE=projectsettings.settings.development_docker_sqlite_settings
+markers =
+ back_end_tests: These are backend tests
+ front_end_tests: these are frontend tests
+ version_increase: these are version increase tests
diff --git a/requirements.txt b/requirements.txt
index 384d388c..57320cb1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1 @@
--r requirements/heroku_requirements.txt
\ No newline at end of file
+-r requirements/prod_requirements.txt
\ No newline at end of file
diff --git a/requirements/base_requirements.txt b/requirements/base_requirements.txt
deleted file mode 100644
index 744c330d..00000000
--- a/requirements/base_requirements.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Django==2.2.9
-django-filebrowser==3.12.1
-lxml==4.4.2
-olefile==0.46
-Pillow==6.2.0
-psycopg2-binary==2.8.4
-pytz==2019.3
-django-grappelli==2.13.3
-djangorestframework==3.11.0
-djangorestframework-xml==1.4.0
-markdown==3.1.1
-django-filter==2.2.0
-pandas==0.25.2
-matplotlib==3.1.1
diff --git a/requirements/development_requirements.txt b/requirements/development_requirements.txt
index b21d05b1..9d379932 100644
--- a/requirements/development_requirements.txt
+++ b/requirements/development_requirements.txt
@@ -1 +1,21 @@
--r base_requirements.txt
+Django==3.2.20
+django-filebrowser==3.14.3
+lxml==5.1.0
+olefile==0.46
+Pillow==7.1.2
+psycopg2-binary==2.8.4
+pytz==2022.4
+django-grappelli==2.15.7
+djangorestframework==3.14.0
+djangorestframework-xml==2.0.0
+markdown==3.1.1
+django-filter==23.5
+pandas==1.5.3
+matplotlib==3.7.5
+pytest>=8.0.0
+pytest-cov>=5.0.0
+pytest-django>=4.7.0
+codacy-coverage>=1.3.11
+selenium>=4.16.0
+factory_boy>=3.3.0
+pylint>=3.1.0
\ No newline at end of file
diff --git a/requirements/heroku_requirements.txt b/requirements/heroku_requirements.txt
deleted file mode 100644
index 6338e1d2..00000000
--- a/requirements/heroku_requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
--r base_requirements.txt
--r test_requirements.txt
-
-gunicorn==19.7.1
-dj-database-url==0.4.2
diff --git a/requirements/prod_requirements.txt b/requirements/prod_requirements.txt
new file mode 100644
index 00000000..625cc8c5
--- /dev/null
+++ b/requirements/prod_requirements.txt
@@ -0,0 +1,14 @@
+Django==3.2.20
+django-filebrowser==3.14.3
+lxml==5.1.0
+olefile==0.46
+Pillow==7.1.2
+psycopg2-binary==2.8.4
+pytz==2022.4
+django-grappelli==2.15.7
+djangorestframework==3.14.0
+djangorestframework-xml==2.0.0
+markdown==3.1.1
+django-filter==23.5
+pandas==1.5.3
+matplotlib==3.7.5
diff --git a/requirements/test_requirements.txt b/requirements/test_requirements.txt
deleted file mode 100644
index 77e44977..00000000
--- a/requirements/test_requirements.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-pytest==3.7.0
-pytest-cov==2.5.1
-pytest-django==3.1.2
-codacy-coverage==1.3.6
-selenium==3.14.0
-factory_boy==2.11.1
-pylint==2.1.1
\ No newline at end of file
diff --git a/setup.py b/setup.py
index e58e5cbd..f91475a3 100644
--- a/setup.py
+++ b/setup.py
@@ -10,24 +10,24 @@
author_email='aaron.riedener@gmail.com',
license='BSD',
packages=find_packages(exclude=["projectsettings", "documentation"]),
- install_requires=['Django==2.2.9',
- 'django-filebrowser==3.12.1',
- 'lxml==4.4.2',
+ install_requires=['Django==3.2.20',
+ 'django-filebrowser==3.14.3',
+ 'lxml==5.1.0',
'olefile==0.46',
- 'Pillow==6.2.0',
+ 'Pillow==7.1.2',
'psycopg2-binary==2.8.4',
- 'pytz==2019.3',
- 'django-grappelli==2.13.3',
- 'djangorestframework==3.11.0',
- 'djangorestframework-xml==1.4.0',
+ 'pytz==2022.4',
+ 'django-grappelli==2.15.7',
+ 'djangorestframework==3.14.0',
+ 'djangorestframework-xml==2.0.0',
'markdown==3.1.1',
- 'django-filter==2.2.0',
- 'pandas==0.25.2',
- 'matplotlib==3.1.1',
+ 'django-filter==23.5',
+ 'pandas==1.5.3',
+ 'matplotlib==3.7.5'
],
zip_safe=False,
classifiers=['Development Status :: 4 - Beta',
- 'Programming Language :: Python :: 3.4', ],
+ 'Programming Language :: Python :: 3.10', ],
python_requires='~=3.5',
include_package_data=True,
)