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, )