Skip to content
Snippets Groups Projects
Verified Commit 76125de8 authored by Tom Teichler's avatar Tom Teichler :beers:
Browse files

Merge branch 'master' into sepaxml

parents 56590967 c1a810ee
No related branches found
No related tags found
1 merge request!16Sepaxml
Pipeline #173153 canceled
Showing
with 443 additions and 52 deletions
module.exports = {
extends: [
"eslint:recommended",
"plugin:vue/strongly-recommended",
"plugin:@intlify/vue-i18n/recommended",
],
rules: {
"no-unused-vars": "warn",
"vue/no-unused-vars": "off",
"vue/multi-word-component-names": "off",
"@intlify/vue-i18n/key-format-style": [
"error",
"snake_case",
{
splitByDots: false,
},
],
// "@intlify/vue-i18n/no-unused-keys": ["warn", {}],
"@intlify/vue-i18n/no-raw-text": [
"error",
{
ignoreNodes: ["v-icon"],
ignorePattern: "^[-–—·#:()\\[\\]&\\.\\s]+$",
},
],
// Fixes for prettier (avoid eslint-config-prettier)
// The following rules can be used in some cases. See the README for more
// information. (These are marked with `0` instead of `"off"` so that a
// script can distinguish them.)
curly: 0,
"lines-around-comment": 0,
"max-len": 0,
"no-confusing-arrow": 0,
"no-mixed-operators": 0,
"no-tabs": 0,
"no-unexpected-multiline": 0,
quotes: 0,
"@typescript-eslint/quotes": 0,
"babel/quotes": 0,
"vue/html-self-closing": 0,
"vue/max-len": 0,
// The rest are rules that you never need to enable when using Prettier.
"array-bracket-newline": "off",
"array-bracket-spacing": "off",
"array-element-newline": "off",
"arrow-parens": "off",
"arrow-spacing": "off",
"block-spacing": "off",
"brace-style": "off",
"comma-dangle": "off",
"comma-spacing": "off",
"comma-style": "off",
"computed-property-spacing": "off",
"dot-location": "off",
"eol-last": "off",
"func-call-spacing": "off",
"function-call-argument-newline": "off",
"function-paren-newline": "off",
"generator-star": "off",
"generator-star-spacing": "off",
"implicit-arrow-linebreak": "off",
indent: "off",
"jsx-quotes": "off",
"key-spacing": "off",
"keyword-spacing": "off",
"linebreak-style": "off",
"multiline-ternary": "off",
"newline-per-chained-call": "off",
"new-parens": "off",
"no-arrow-condition": "off",
"no-comma-dangle": "off",
"no-extra-parens": "off",
"no-extra-semi": "off",
"no-floating-decimal": "off",
"no-mixed-spaces-and-tabs": "off",
"no-multi-spaces": "off",
"no-multiple-empty-lines": "off",
"no-reserved-keys": "off",
"no-space-before-semi": "off",
"no-trailing-spaces": "off",
"no-whitespace-before-property": "off",
"no-wrap-func": "off",
"nonblock-statement-body-position": "off",
"object-curly-newline": "off",
"object-curly-spacing": "off",
"object-property-newline": "off",
"one-var-declaration-per-line": "off",
"operator-linebreak": "off",
"padded-blocks": "off",
"quote-props": "off",
"rest-spread-spacing": "off",
semi: "off",
"semi-spacing": "off",
"semi-style": "off",
"space-after-function-name": "off",
"space-after-keywords": "off",
"space-before-blocks": "off",
"space-before-function-paren": "off",
"space-before-function-parentheses": "off",
"space-before-keywords": "off",
"space-in-brackets": "off",
"space-in-parens": "off",
"space-infix-ops": "off",
"space-return-throw-case": "off",
"space-unary-ops": "off",
"space-unary-word-ops": "off",
"switch-colon-spacing": "off",
"template-curly-spacing": "off",
"template-tag-spacing": "off",
"unicode-bom": "off",
"wrap-iife": "off",
"wrap-regex": "off",
"yield-star-spacing": "off",
"@babel/object-curly-spacing": "off",
"@babel/semi": "off",
"@typescript-eslint/brace-style": "off",
"@typescript-eslint/comma-dangle": "off",
"@typescript-eslint/comma-spacing": "off",
"@typescript-eslint/func-call-spacing": "off",
"@typescript-eslint/indent": "off",
"@typescript-eslint/keyword-spacing": "off",
"@typescript-eslint/member-delimiter-style": "off",
"@typescript-eslint/no-extra-parens": "off",
"@typescript-eslint/no-extra-semi": "off",
"@typescript-eslint/object-curly-spacing": "off",
"@typescript-eslint/semi": "off",
"@typescript-eslint/space-before-blocks": "off",
"@typescript-eslint/space-before-function-paren": "off",
"@typescript-eslint/space-infix-ops": "off",
"@typescript-eslint/type-annotation-spacing": "off",
"babel/object-curly-spacing": "off",
"babel/semi": "off",
"flowtype/boolean-style": "off",
"flowtype/delimiter-dangle": "off",
"flowtype/generic-spacing": "off",
"flowtype/object-type-curly-spacing": "off",
"flowtype/object-type-delimiter": "off",
"flowtype/quotes": "off",
"flowtype/semi": "off",
"flowtype/space-after-type-colon": "off",
"flowtype/space-before-generic-bracket": "off",
"flowtype/space-before-type-colon": "off",
"flowtype/union-intersection-spacing": "off",
"react/jsx-child-element-spacing": "off",
"react/jsx-closing-bracket-location": "off",
"react/jsx-closing-tag-location": "off",
"react/jsx-curly-newline": "off",
"react/jsx-curly-spacing": "off",
"react/jsx-equals-spacing": "off",
"react/jsx-first-prop-new-line": "off",
"react/jsx-indent": "off",
"react/jsx-indent-props": "off",
"react/jsx-max-props-per-line": "off",
"react/jsx-newline": "off",
"react/jsx-one-expression-per-line": "off",
"react/jsx-props-no-multi-spaces": "off",
"react/jsx-tag-spacing": "off",
"react/jsx-wrap-multilines": "off",
"standard/array-bracket-even-spacing": "off",
"standard/computed-property-even-spacing": "off",
"standard/object-curly-even-spacing": "off",
"unicorn/empty-brace-spaces": "off",
"unicorn/no-nested-ternary": "off",
"unicorn/number-literal-case": "off",
"vue/array-bracket-newline": "off",
"vue/array-bracket-spacing": "off",
"vue/arrow-spacing": "off",
"vue/block-spacing": "off",
"vue/block-tag-newline": "off",
"vue/brace-style": "off",
"vue/comma-dangle": "off",
"vue/comma-spacing": "off",
"vue/comma-style": "off",
"vue/dot-location": "off",
"vue/func-call-spacing": "off",
"vue/html-closing-bracket-newline": "off",
"vue/html-closing-bracket-spacing": "off",
"vue/html-end-tags": "off",
"vue/html-indent": "off",
"vue/html-quotes": "off",
"vue/key-spacing": "off",
"vue/keyword-spacing": "off",
"vue/max-attributes-per-line": "off",
"vue/multiline-html-element-content-newline": "off",
"vue/multiline-ternary": "off",
"vue/mustache-interpolation-spacing": "off",
"vue/no-extra-parens": "off",
"vue/no-multi-spaces": "off",
"vue/no-spaces-around-equal-signs-in-attribute": "off",
"vue/object-curly-newline": "off",
"vue/object-curly-spacing": "off",
"vue/object-property-newline": "off",
"vue/operator-linebreak": "off",
"vue/quote-props": "off",
"vue/script-indent": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/space-in-parens": "off",
"vue/space-infix-ops": "off",
"vue/space-unary-ops": "off",
"vue/template-curly-spacing": "off",
},
settings: {
"vue-i18n": {
localeDir: "./aleksis/core/frontend/messages/*.{json}",
messageSyntaxVersion: "^8.0.0",
},
},
env: {
es2021: true,
},
parserOptions: {
ecmaVersion: "latest",
},
};
......@@ -52,6 +52,11 @@ DEADJOE
.idea
.idea/
# VSCode
.vscode/
.history/
*.code-workspace
# Database
db.sqlite3
......@@ -62,15 +67,28 @@ docs/_build/
*.aux
# Generated files
aleksis/node_modules/
aleksis/static/
/cache
/node_modules
.dev-js/node_modules
/static/
/whoosh_index/
.vite
.dev-js/.yarn
.dev-js/.pnp.cjs
.dev-js/.pnp.loader.mjs
# Lock files
poetry.lock
package-lock.json
yarn.lock
.dev-js/yarn.lock
# Tests
.coverage
.mypy_cache/
.tox/
htmlcov/
# Data
maintenance_mode_state.txt
media/
package-lock.json
poetry.lock
include:
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/prepare/lock.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/lint.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/publish/pypi.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/docker/image.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/prepare/lock.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/lint.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/publish/pypi.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/docker/image.yml
# Byte-compiled / optimized / DLL files
*$py.class
*.py[cod]
__pycache__/
# Distribution / packaging
*.egg
*.egg-info/
.Python
.eggs/
.installed.cfg
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
# Installer logs
pip-delete-this-directory.txt
pip-log.txt
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# pyenv
.python-version
# Environments
.env
.venv
ENV/
env/
venv/
# Editors
*~
DEADJOE
\#*#
# IntelliJ
.idea
.idea/
# Database
db.sqlite3
# Sphinx
docs/_build/
# TeX
*.aux
# Generated files
/node_modules/
/static/
/whoosh_index/
poetry.lock
.coverage
.mypy_cache/
.tox/
htmlcov/
maintenance_mode_state.txt
media/
package-lock.json
yarn.lock
# VSCode
.vscode/
.history/
*.code-workspace
/cache
# Add HTML files to avoid problems with unsupported Django templates
*.html
# Do not check/reformat generated files
aleksis/core/util/licenses.json
.vite/
.pnp.cjs
.pnp.loader.mjs
......@@ -74,7 +74,24 @@ class EditClientForm(ExtensibleForm):
class Meta:
model = Client
exclude = []
fields = [
"name",
"email",
"pledge_enabled",
"sofort_enabled",
"sofort_api_id",
"sofort_api_key",
"sofort_project_id",
"paypal_enabled",
"paypal_client_id",
"paypal_secret",
"paypal_capture",
"sdd_enabled",
"sdd_creditor",
"sdd_creditor_identifier",
"sdd_iban",
"sdd_bic",
]
class EditInvoiceGroupForm(ExtensibleForm):
......@@ -83,4 +100,4 @@ class EditInvoiceGroupForm(ExtensibleForm):
class Meta:
model = InvoiceGroup
exclude = ["client"]
fields = ["name", "template_name"]
import { hasPersonValidator } from "aleksis.core/routeValidators";
export default {
meta: {
inMenu: true,
......@@ -131,5 +129,5 @@ export default {
},
name: "tezor.sendInvoiceByToken",
},
],
],
};
......@@ -337,7 +337,7 @@ msgid "Pay now"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/full.html:113
msgid "Mark as payed"
msgid "Mark as paid"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/list.html:6
......
......@@ -365,7 +365,7 @@ msgid "Pay now"
msgstr "Jetzt zahlen"
#: aleksis/apps/tezor/templates/tezor/invoice/full.html:113
msgid "Mark as payed"
msgid "Mark as paid"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/list.html:6
......
......@@ -337,7 +337,7 @@ msgid "Pay now"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/full.html:113
msgid "Mark as payed"
msgid "Mark as paid"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/list.html:6
......
......@@ -336,7 +336,7 @@ msgid "Pay now"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/full.html:113
msgid "Mark as payed"
msgid "Mark as paid"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/list.html:6
......
......@@ -336,7 +336,7 @@ msgid "Pay now"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/full.html:113
msgid "Mark as payed"
msgid "Mark as paid"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/list.html:6
......
......@@ -336,7 +336,7 @@ msgid "Pay now"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/full.html:113
msgid "Mark as payed"
msgid "Mark as paid"
msgstr ""
#: aleksis/apps/tezor/templates/tezor/invoice/list.html:6
......
# Generated by Django 3.2.12 on 2022-03-06 21:33
import aleksis.core.mixins
import django.contrib.sites.managers
import aleksis.core.managers
from django.db import migrations, models
import django.db.models.deletion
......@@ -25,7 +25,7 @@ class Migration(migrations.Migration):
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
],
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
('objects', aleksis.core.managers.AlekSISBaseManager()),
],
),
migrations.CreateModel(
......@@ -39,7 +39,7 @@ class Migration(migrations.Migration):
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
],
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
('objects', aleksis.core.managers.AlekSISBaseManager()),
],
),
migrations.CreateModel(
......
# Generated by Django 3.2.12 on 2022-03-12 21:41
import django.contrib.sites.managers
import aleksis.core.managers
from django.db import migrations, models
import django.db.models.deletion
......@@ -29,7 +29,7 @@ class Migration(migrations.Migration):
'abstract': False,
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
('objects', aleksis.core.managers.AlekSISBaseManager()),
],
),
migrations.AddField(
......
......@@ -39,7 +39,7 @@ def configure_clients(apps, schema_editor):
values[f"{variant}_enabled"] = False
warnings.warn(f"Payment variant {variant} enabled but {field.name} not configured!")
Client.objects.update(**values)
Client._base_manager.update(**values)
class Migration(migrations.Migration):
......
# Generated by Django 4.2.3 on 2023-07-22 15:41
import aleksis.core.managers
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('sites', '0002_alter_domain_unique'),
('tezor', '0009_invoice_billing_phone'),
]
operations = [
migrations.AddField(
model_name='client',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='invoicegroup',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='invoiceitem',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
]
......@@ -54,6 +54,8 @@ class Client(ExtensibleModel):
pledge_enabled = models.BooleanField(verbose_name=_("Pledge enabled"), default=False)
class Meta:
verbose_name = _("Client")
verbose_name_plural = _("Clients")
constraints = [
models.UniqueConstraint(fields=["name", "site"], name="uniq_client_per_site"),
models.CheckConstraint(
......
......@@ -28,6 +28,13 @@ class InvoiceGroup(ExtensibleModel):
verbose_name=_("Template to render invoices with as PDF"), blank=True, max_length=255
)
class Meta:
verbose_name = _("Invoice Group")
verbose_name_plural = _("Invoice Groups")
constraints = [
models.UniqueConstraint(fields=["client", "name"], name="group_uniq_per_client")
]
def __str__(self) -> str:
return self.name
......@@ -37,11 +44,6 @@ class InvoiceGroup(ExtensibleModel):
else:
return Client.get_variant_choices()
class Meta:
constraints = [
models.UniqueConstraint(fields=["client", "name"], name="group_uniq_per_client")
]
class Invoice(BasePayment, PureDjangoModel):
STATUS_ICONS = {
......@@ -81,6 +83,17 @@ class Invoice(BasePayment, PureDjangoModel):
)
items = models.ManyToManyField("InvoiceItem", verbose_name=_("Invoice items"))
class Meta:
verbose_name = _("Invoice")
verbose_name_plural = _("Invoices")
constraints = [
models.UniqueConstraint(fields=["number", "group"], name="number_uniq_per_group"),
]
permissions = (("send_invoice_email", _("Can send invoice by email")),)
def __str__(self):
return self.number
def save(self, *args, **kwargs):
if self.person:
person = self.person
......@@ -104,6 +117,9 @@ class Invoice(BasePayment, PureDjangoModel):
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("invoice_by_token", kwargs={"slug": self.token})
def get_variant_choices(self=None):
if self and self.group:
return self.group.get_variant_choices()
......@@ -137,12 +153,6 @@ class Invoice(BasePayment, PureDjangoModel):
return None
class Meta:
constraints = [
models.UniqueConstraint(fields=["number", "group"], name="number_uniq_per_group"),
]
permissions = (("send_invoice_email", _("Can send invoice by email")),)
def get_billing_email_recipients(self):
if hasattr(self.for_object, "get_billing_email_recipients"):
return self.for_object.get_billing_email_recipients()
......@@ -182,9 +192,6 @@ class Invoice(BasePayment, PureDjangoModel):
return TotalsTable(values)
def get_absolute_url(self):
return reverse("invoice_by_token", kwargs={"slug": self.token})
def get_success_url(self):
return self.get_absolute_url()
......@@ -203,6 +210,13 @@ class InvoiceItem(ExtensibleModel):
verbose_name=_("Tax rate"), max_digits=4, decimal_places=1, default="0.0"
)
class Meta:
verbose_name = _("Invoice Item")
verbose_name_plural = _("Invoice Items")
def __str__(self):
return f"{self.sku}: {self.description}"
def as_purchased_item(self):
return PurchasedItem(
name=self.description,
......
......@@ -154,5 +154,7 @@ rules.add_perm("tezor.send_invoice_email_rule", send_invoice_email_predicate)
view_own_invoices_predicate = has_person
rules.add_perm("tezor.view_own_invoices_list_rule", view_own_invoices_predicate)
view_menu_predicate = view_own_invoices_predicate | view_clients_predicate | view_invoice_groups_predicate
view_menu_predicate = (
view_own_invoices_predicate | view_clients_predicate | view_invoice_groups_predicate
)
rules.add_perm("tezor.view_menu_rule", view_menu_predicate)
......@@ -102,7 +102,7 @@ class InvoicesTable(tables.Table):
verbose_name=_("View"),
text=_("View"),
)
print = tables.LinkColumn(
print_action = tables.LinkColumn(
"print_invoice",
args=[A("token")],
verbose_name=_("Print"),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment