wbaccounting 2.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. wbaccounting-2.2.1/.gitignore +181 -0
  2. wbaccounting-2.2.1/PKG-INFO +8 -0
  3. wbaccounting-2.2.1/pyproject.toml +31 -0
  4. wbaccounting-2.2.1/wbaccounting/__init__.py +1 -0
  5. wbaccounting-2.2.1/wbaccounting/admin/__init__.py +5 -0
  6. wbaccounting-2.2.1/wbaccounting/admin/booking_entry.py +53 -0
  7. wbaccounting-2.2.1/wbaccounting/admin/entry_accounting_information.py +10 -0
  8. wbaccounting-2.2.1/wbaccounting/admin/invoice.py +26 -0
  9. wbaccounting-2.2.1/wbaccounting/admin/invoice_type.py +8 -0
  10. wbaccounting-2.2.1/wbaccounting/admin/transactions.py +16 -0
  11. wbaccounting-2.2.1/wbaccounting/apps.py +5 -0
  12. wbaccounting-2.2.1/wbaccounting/dynamic_preferences_registry.py +107 -0
  13. wbaccounting-2.2.1/wbaccounting/factories/__init__.py +10 -0
  14. wbaccounting-2.2.1/wbaccounting/factories/booking_entry.py +21 -0
  15. wbaccounting-2.2.1/wbaccounting/factories/entry_accounting_information.py +46 -0
  16. wbaccounting-2.2.1/wbaccounting/factories/invoice.py +43 -0
  17. wbaccounting-2.2.1/wbaccounting/factories/transactions.py +32 -0
  18. wbaccounting-2.2.1/wbaccounting/files/__init__.py +0 -0
  19. wbaccounting-2.2.1/wbaccounting/files/invoice_document_file.py +134 -0
  20. wbaccounting-2.2.1/wbaccounting/files/utils.py +331 -0
  21. wbaccounting-2.2.1/wbaccounting/fixtures/accounting.json +578 -0
  22. wbaccounting-2.2.1/wbaccounting/generators/__init__.py +6 -0
  23. wbaccounting-2.2.1/wbaccounting/generators/base.py +120 -0
  24. wbaccounting-2.2.1/wbaccounting/io/handlers/__init__.py +0 -0
  25. wbaccounting-2.2.1/wbaccounting/io/handlers/transactions.py +32 -0
  26. wbaccounting-2.2.1/wbaccounting/io/parsers/__init__.py +0 -0
  27. wbaccounting-2.2.1/wbaccounting/io/parsers/societe_generale_lux.py +49 -0
  28. wbaccounting-2.2.1/wbaccounting/io/parsers/societe_generale_lux_prenotification.py +60 -0
  29. wbaccounting-2.2.1/wbaccounting/migrations/0001_initial_squashed_squashed_0005_alter_bookingentry_counterparty_and_more.py +284 -0
  30. wbaccounting-2.2.1/wbaccounting/migrations/0006_alter_invoice_status.py +30 -0
  31. wbaccounting-2.2.1/wbaccounting/migrations/0007_alter_invoice_options.py +23 -0
  32. wbaccounting-2.2.1/wbaccounting/migrations/0008_alter_invoice_options.py +20 -0
  33. wbaccounting-2.2.1/wbaccounting/migrations/0009_invoicetype_alter_bookingentry_options_and_more.py +366 -0
  34. wbaccounting-2.2.1/wbaccounting/migrations/0010_alter_bookingentry_options.py +20 -0
  35. wbaccounting-2.2.1/wbaccounting/migrations/0011_transaction.py +103 -0
  36. wbaccounting-2.2.1/wbaccounting/migrations/0012_entryaccountinginformation_external_invoice_users.py +25 -0
  37. wbaccounting-2.2.1/wbaccounting/migrations/__init__.py +0 -0
  38. wbaccounting-2.2.1/wbaccounting/models/__init__.py +6 -0
  39. wbaccounting-2.2.1/wbaccounting/models/booking_entry.py +167 -0
  40. wbaccounting-2.2.1/wbaccounting/models/entry_accounting_information.py +157 -0
  41. wbaccounting-2.2.1/wbaccounting/models/invoice.py +467 -0
  42. wbaccounting-2.2.1/wbaccounting/models/invoice_type.py +30 -0
  43. wbaccounting-2.2.1/wbaccounting/models/model_tasks.py +71 -0
  44. wbaccounting-2.2.1/wbaccounting/models/transactions.py +112 -0
  45. wbaccounting-2.2.1/wbaccounting/permissions.py +6 -0
  46. wbaccounting-2.2.1/wbaccounting/processors/__init__.py +0 -0
  47. wbaccounting-2.2.1/wbaccounting/processors/dummy_processor.py +5 -0
  48. wbaccounting-2.2.1/wbaccounting/serializers/__init__.py +12 -0
  49. wbaccounting-2.2.1/wbaccounting/serializers/booking_entry.py +78 -0
  50. wbaccounting-2.2.1/wbaccounting/serializers/consolidated_invoice.py +109 -0
  51. wbaccounting-2.2.1/wbaccounting/serializers/entry_accounting_information.py +149 -0
  52. wbaccounting-2.2.1/wbaccounting/serializers/invoice.py +95 -0
  53. wbaccounting-2.2.1/wbaccounting/serializers/invoice_type.py +16 -0
  54. wbaccounting-2.2.1/wbaccounting/serializers/transactions.py +50 -0
  55. wbaccounting-2.2.1/wbaccounting/tests/__init__.py +0 -0
  56. wbaccounting-2.2.1/wbaccounting/tests/conftest.py +65 -0
  57. wbaccounting-2.2.1/wbaccounting/tests/test_displays/__init__.py +0 -0
  58. wbaccounting-2.2.1/wbaccounting/tests/test_displays/test_booking_entries.py +1 -0
  59. wbaccounting-2.2.1/wbaccounting/tests/test_models/__init__.py +0 -0
  60. wbaccounting-2.2.1/wbaccounting/tests/test_models/test_booking_entries.py +119 -0
  61. wbaccounting-2.2.1/wbaccounting/tests/test_models/test_entry_accounting_information.py +81 -0
  62. wbaccounting-2.2.1/wbaccounting/tests/test_models/test_invoice_types.py +21 -0
  63. wbaccounting-2.2.1/wbaccounting/tests/test_models/test_invoices.py +73 -0
  64. wbaccounting-2.2.1/wbaccounting/tests/test_models/test_transactions.py +40 -0
  65. wbaccounting-2.2.1/wbaccounting/tests/test_processors.py +28 -0
  66. wbaccounting-2.2.1/wbaccounting/tests/test_serializers/__init__.py +0 -0
  67. wbaccounting-2.2.1/wbaccounting/tests/test_serializers/test_booking_entries.py +69 -0
  68. wbaccounting-2.2.1/wbaccounting/tests/test_serializers/test_entry_accounting_information.py +64 -0
  69. wbaccounting-2.2.1/wbaccounting/tests/test_serializers/test_invoice_types.py +35 -0
  70. wbaccounting-2.2.1/wbaccounting/tests/test_serializers/test_transactions.py +72 -0
  71. wbaccounting-2.2.1/wbaccounting/urls.py +68 -0
  72. wbaccounting-2.2.1/wbaccounting/viewsets/__init__.py +12 -0
  73. wbaccounting-2.2.1/wbaccounting/viewsets/booking_entry.py +61 -0
  74. wbaccounting-2.2.1/wbaccounting/viewsets/buttons/__init__.py +3 -0
  75. wbaccounting-2.2.1/wbaccounting/viewsets/buttons/booking_entry.py +15 -0
  76. wbaccounting-2.2.1/wbaccounting/viewsets/buttons/entry_accounting_information.py +100 -0
  77. wbaccounting-2.2.1/wbaccounting/viewsets/buttons/invoice.py +65 -0
  78. wbaccounting-2.2.1/wbaccounting/viewsets/cashflows.py +124 -0
  79. wbaccounting-2.2.1/wbaccounting/viewsets/display/__init__.py +8 -0
  80. wbaccounting-2.2.1/wbaccounting/viewsets/display/booking_entry.py +58 -0
  81. wbaccounting-2.2.1/wbaccounting/viewsets/display/cashflows.py +58 -0
  82. wbaccounting-2.2.1/wbaccounting/viewsets/display/entry_accounting_information.py +91 -0
  83. wbaccounting-2.2.1/wbaccounting/viewsets/display/invoice.py +218 -0
  84. wbaccounting-2.2.1/wbaccounting/viewsets/display/invoice_type.py +19 -0
  85. wbaccounting-2.2.1/wbaccounting/viewsets/display/transactions.py +35 -0
  86. wbaccounting-2.2.1/wbaccounting/viewsets/endpoints/__init__.py +1 -0
  87. wbaccounting-2.2.1/wbaccounting/viewsets/endpoints/invoice.py +6 -0
  88. wbaccounting-2.2.1/wbaccounting/viewsets/entry_accounting_information.py +143 -0
  89. wbaccounting-2.2.1/wbaccounting/viewsets/invoice.py +277 -0
  90. wbaccounting-2.2.1/wbaccounting/viewsets/invoice_type.py +25 -0
  91. wbaccounting-2.2.1/wbaccounting/viewsets/menu/__init__.py +6 -0
  92. wbaccounting-2.2.1/wbaccounting/viewsets/menu/booking_entry.py +15 -0
  93. wbaccounting-2.2.1/wbaccounting/viewsets/menu/cashflows.py +10 -0
  94. wbaccounting-2.2.1/wbaccounting/viewsets/menu/entry_accounting_information.py +11 -0
  95. wbaccounting-2.2.1/wbaccounting/viewsets/menu/invoice.py +15 -0
  96. wbaccounting-2.2.1/wbaccounting/viewsets/menu/invoice_type.py +15 -0
  97. wbaccounting-2.2.1/wbaccounting/viewsets/menu/transactions.py +15 -0
  98. wbaccounting-2.2.1/wbaccounting/viewsets/titles/__init__.py +4 -0
  99. wbaccounting-2.2.1/wbaccounting/viewsets/titles/booking_entry.py +12 -0
  100. wbaccounting-2.2.1/wbaccounting/viewsets/titles/entry_accounting_information.py +12 -0
  101. wbaccounting-2.2.1/wbaccounting/viewsets/titles/invoice.py +23 -0
  102. wbaccounting-2.2.1/wbaccounting/viewsets/titles/invoice_type.py +12 -0
  103. wbaccounting-2.2.1/wbaccounting/viewsets/transactions.py +34 -0
@@ -0,0 +1,181 @@
1
+ ~
2
+
3
+ # Docker volumes
4
+ volumes/
5
+ # Poetry auth file
6
+ auth.toml
7
+
8
+ media/*
9
+ media/
10
+ mediafiles/
11
+ mediafiles/*
12
+ test/*
13
+ staticfiles/*
14
+ staticfiles/
15
+ #
16
+ # Byte-compiled / optimized / DLL files
17
+ __pycache__/
18
+ *.py[cod]
19
+ *$py.class
20
+
21
+ # C extensions
22
+ *.so
23
+
24
+ # Distribution / packaging
25
+ .Python
26
+ build/
27
+ develop-eggs/
28
+ dist/
29
+ info/
30
+ downloads/
31
+ eggs/
32
+ .eggs/
33
+ lib/
34
+ lib64/
35
+ parts/
36
+ sdist/
37
+ var/
38
+ wheels/
39
+ share/python-wheels/
40
+ *.egg-info/
41
+ .installed.cfg
42
+ *.egg
43
+ MANIFEST
44
+
45
+ # PyInstaller
46
+ # Usually these files are written by a python script from a template
47
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
48
+ *.manifest
49
+ *.spec
50
+
51
+ # Installer logs
52
+ pip-log.txt
53
+ pip-delete-this-directory.txt
54
+
55
+ # Unit test / coverage reports
56
+ htmlcov/
57
+ .tox/
58
+ .nox/
59
+ .coverage
60
+ .coverage.*
61
+ .cache
62
+ .dccache
63
+ nosetests.xml
64
+ coverage.xml
65
+ *.cover
66
+ *.py,cover
67
+ .hypothesis/
68
+ .pytest_cache/
69
+ cover/
70
+ report.xml
71
+ */report.xml
72
+
73
+ # Translations
74
+ *.mo
75
+ *.pot
76
+
77
+ # Django stuff:
78
+ *.log
79
+ local_settings.py
80
+ *.sqlite3
81
+ db.sqlite3-journal
82
+
83
+ # Flask stuff:
84
+ instance/
85
+ .webassets-cache
86
+
87
+ # Scrapy stuff:
88
+ .scrapy
89
+
90
+ # Sphinx documentation
91
+ docs/_build/
92
+
93
+ # PyBuilder
94
+ .pybuilder/
95
+ target/
96
+
97
+ # Jupyter Notebook
98
+ .ipynb_checkpoints
99
+ *.ipynb
100
+ # IPython
101
+ profile_default/
102
+ ipython_config.py
103
+
104
+ # pyenv
105
+ # For a library or package, you might want to ignore these files since the code is
106
+ # intended to run in multiple environments; otherwise, check them in:
107
+ # .python-version
108
+
109
+ # pipenv
110
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
111
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
112
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
113
+ # install all needed dependencies.
114
+ #Pipfile.lock
115
+
116
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
117
+ __pypackages__/
118
+
119
+ # Celery stuff
120
+ celerybeat-schedule
121
+ celerybeat.pid
122
+
123
+ # SageMath parsed files
124
+ *.sage.py
125
+
126
+ # Environments
127
+ .env
128
+ .envrc
129
+ .venv
130
+ env/
131
+ venv/
132
+ ENV/
133
+ env.bak/
134
+ venv.bak/
135
+ .vscode/
136
+ .idea/
137
+ .idea.bkp/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+ crm/
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # Gitlab Runner
164
+ builds
165
+ builds/
166
+
167
+ # Integrator Office 365 : reverse proxy tunnel for outlook365
168
+ ngrok
169
+ */ngrok
170
+ /modules/**/system/
171
+
172
+ /modules/wbmailing/files/*
173
+ /modules/wbmailing/mailing/*
174
+
175
+ /projects/*/requirements.txt
176
+ public
177
+
178
+ # Ignore archive localization generated folder
179
+ backend/modules/**/archive/*
180
+ **/**/requirements.txt
181
+ CHANGELOG-*
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.3
2
+ Name: wbaccounting
3
+ Version: 2.2.1
4
+ Summary: A workbench module for managing invoicing and simple accounting.
5
+ Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
6
+ Requires-Dist: reportlab==3.*
7
+ Requires-Dist: schwifty==2024.5.*
8
+ Requires-Dist: wbcore
@@ -0,0 +1,31 @@
1
+ [project]
2
+ name = "wbaccounting"
3
+ description = "A workbench module for managing invoicing and simple accounting."
4
+ authors = [{ name = "Christopher Wittlinger", email = "c.wittlinger@stainly.com"}]
5
+ dynamic = ["version"]
6
+
7
+ dependencies = [
8
+ "wbcore",
9
+ "reportlab == 3.*",
10
+ "schwifty == 2024.5.*",
11
+ ]
12
+
13
+ [tool.uv.sources]
14
+ wbcore = { workspace = true }
15
+
16
+ [tool.uv]
17
+ package = true
18
+
19
+ [tool.hatch.version]
20
+ path = "../../pyproject.toml"
21
+
22
+ [tool.hatch.build.targets.sdist]
23
+ include = ["wbaccounting/*"]
24
+
25
+ [tool.hatch.build.targets.wheel]
26
+ packages = ["wbaccounting"]
27
+ only-packages = true
28
+
29
+ [build-system]
30
+ requires = ["hatchling"]
31
+ build-backend = "hatchling.build"
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,5 @@
1
+ from .booking_entry import BookingEntryInline, BookingEntryModelAdmin
2
+ from .entry_accounting_information import EntryAccountingInformationModelAdmin
3
+ from .invoice_type import InvoiceTypeModelAdmin
4
+ from .invoice import InvoiceModelAdmin
5
+ from .transactions import TransactionModelAdmin
@@ -0,0 +1,53 @@
1
+ from datetime import date
2
+
3
+ from django.contrib import admin
4
+ from wbaccounting.models import BookingEntry, Invoice
5
+ from wbcore.contrib.directory.models import Entry
6
+
7
+
8
+ class BookingEntryInline(admin.TabularInline):
9
+ model = BookingEntry
10
+ fields = ("booking_date", "net_value", "vat")
11
+ ordering = ("vat", "title")
12
+
13
+ def has_add_permission(self, request, obj=None):
14
+ return False
15
+
16
+
17
+ @admin.register(BookingEntry)
18
+ class BookingEntryModelAdmin(admin.ModelAdmin):
19
+ list_display = (
20
+ "title",
21
+ "booking_date",
22
+ "net_value",
23
+ "vat",
24
+ "currency",
25
+ "payment_date",
26
+ "counterparty",
27
+ "reference_date",
28
+ )
29
+ search_fields = ["counterparty__computed_str"]
30
+ autocomplete_fields = ("counterparty", "currency")
31
+
32
+ # TODO: Remove or adjust.
33
+ def create_invoice(self, request, queryset):
34
+ counterparty = list(set(queryset.values_list("counterparty__id", flat=True)))
35
+ if len(counterparty) == 1:
36
+ counterparty = Entry.objects.get(id=counterparty[0])
37
+ invoice = Invoice.objects.create(
38
+ title=f"Rebate Invoice {counterparty.computed_str} ({queryset.earliest('from_date').from_date:%d.%m.%Y} - {queryset.latest('to_date').to_date:%d.%m.%Y})",
39
+ invoice_date=date.today(),
40
+ reference_date=date.today(),
41
+ counterparty=counterparty,
42
+ invoice_currency=counterparty.entry_accounting_information.default_currency,
43
+ is_counterparty_invoice=True,
44
+ )
45
+ queryset.update(invoice=invoice)
46
+ invoice.save()
47
+
48
+ else:
49
+ print("-------------------------------") # noqa: T201
50
+ print(f"Too many counterparties selected ({len(counterparty)})") # noqa: T201
51
+ print("-------------------------------") # noqa: T201
52
+
53
+ actions = [create_invoice]
@@ -0,0 +1,10 @@
1
+ from django.contrib import admin
2
+ from wbaccounting.models import EntryAccountingInformation
3
+
4
+
5
+ @admin.register(EntryAccountingInformation)
6
+ class EntryAccountingInformationModelAdmin(admin.ModelAdmin):
7
+ list_display = ("entry", "send_mail", "counterparty_is_private")
8
+ autocomplete_fields = ["default_currency", "entry", "email_to", "email_cc", "email_bcc", "exempt_users"]
9
+
10
+ search_fields = ["entry__computed_str"]
@@ -0,0 +1,26 @@
1
+ from django.contrib import admin
2
+ from wbaccounting.admin import BookingEntryInline
3
+ from wbaccounting.models import Invoice
4
+ from wbcore.contrib.documents.admin import DocumentInLine
5
+
6
+
7
+ @admin.register(Invoice)
8
+ class InvoiceModelAdmin(admin.ModelAdmin):
9
+ fsm_field = ["status"]
10
+ search_fields = ("counterparty__computed_str", "title", "invoice_type__name")
11
+ list_display = (
12
+ "status",
13
+ "title",
14
+ "gross_value",
15
+ "net_value",
16
+ "invoice_date",
17
+ "invoice_currency",
18
+ "counterparty",
19
+ "invoice_type",
20
+ "reference_date",
21
+ )
22
+
23
+ autocomplete_fields = ("counterparty",)
24
+ inlines = [BookingEntryInline, DocumentInLine]
25
+
26
+ raw_id_fields = ["counterparty", "invoice_currency", "invoice_type"]
@@ -0,0 +1,8 @@
1
+ from django.contrib import admin
2
+ from wbaccounting.models import InvoiceType
3
+
4
+
5
+ @admin.register(InvoiceType)
6
+ class InvoiceTypeModelAdmin(admin.ModelAdmin):
7
+ search_fields = ("name", "processor")
8
+ list_display = ("id", "name", "processor")
@@ -0,0 +1,16 @@
1
+ from django.contrib import admin
2
+ from wbaccounting.models import Transaction
3
+
4
+
5
+ @admin.register(Transaction)
6
+ class TransactionModelAdmin(admin.ModelAdmin):
7
+ list_display = ["booking_date", "value_date", "value", "bank_account", "prenotification"]
8
+
9
+ raw_id_fields = ["import_source"]
10
+
11
+ autocomplete_fields = [
12
+ "bank_account",
13
+ "from_bank_account",
14
+ "to_bank_account",
15
+ "currency",
16
+ ]
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class WbaccountingConfig(AppConfig):
5
+ name = "wbaccounting"
@@ -0,0 +1,107 @@
1
+ from django.conf import settings
2
+ from dynamic_preferences.preferences import Section
3
+ from dynamic_preferences.registries import global_preferences_registry
4
+ from dynamic_preferences.types import (
5
+ IntegerPreference,
6
+ LongStringPreference,
7
+ ModelMultipleChoicePreference,
8
+ StringPreference,
9
+ )
10
+ from wbcore.contrib.currency.models import Currency
11
+ from wbcore.contrib.directory.models import Person
12
+
13
+ accounting_section = Section("wbaccounting")
14
+
15
+
16
+ def format_invoice_number(number):
17
+ global_preferences = global_preferences_registry.manager()
18
+ ts = global_preferences["wbaccounting__invoice_thousand_seperator"]
19
+ ds = global_preferences["wbaccounting__invoice_decimal_seperator"]
20
+ if not number:
21
+ number = 0
22
+ s = "{:,.2f}".format(number)
23
+ s = s.replace(",", "//")
24
+ s = s.replace(".", "\\")
25
+
26
+ return s.replace("//", ts).replace("\\", ds)
27
+
28
+
29
+ @global_preferences_registry.register
30
+ class DefaultEntryAccountingInformationCurrency(StringPreference):
31
+ section = accounting_section
32
+ name = "default_entry_account_information_currency_key"
33
+ default = "CHF"
34
+
35
+ verbose_name = "The currency key used for the default currency of newly created entry accounting informations."
36
+
37
+ def validate(self, value):
38
+ if not Currency.objects.filter(key=value).exists():
39
+ return ValueError("The specified currency key is not valid")
40
+
41
+
42
+ @global_preferences_registry.register
43
+ class ExternalEmailAddress(StringPreference):
44
+ section = accounting_section
45
+ name = "external_email_address"
46
+ default = ""
47
+
48
+ verbose_name = "External Email Address"
49
+ help_text = "The Email Address used to send Invoices to the external party."
50
+
51
+
52
+ @global_preferences_registry.register
53
+ class InvoiceEmailBody(LongStringPreference):
54
+ section = accounting_section
55
+ name = "invoice_email_body"
56
+ default = ""
57
+
58
+ verbose_name = "The default E-Mail Body used for emailing Invoices"
59
+
60
+
61
+ @global_preferences_registry.register
62
+ class InvoiceThousandSeperatorPreference(StringPreference):
63
+ section = accounting_section
64
+ name = "invoice_thousand_seperator"
65
+ default = ","
66
+
67
+ verbose_name = "Invoice Thousand Seperator"
68
+ help_text = "Thousand Seperator for Invoices"
69
+
70
+
71
+ @global_preferences_registry.register
72
+ class InvoiceDecimalSeperatorPreference(StringPreference):
73
+ section = accounting_section
74
+ name = "invoice_decimal_seperator"
75
+ default = "."
76
+
77
+ verbose_name = "Invoice Decimal Seperator"
78
+ help_text = "Decimal Seperator for Invoices"
79
+
80
+
81
+ @global_preferences_registry.register
82
+ class InvoiceSignerPreference(ModelMultipleChoicePreference):
83
+ section = accounting_section
84
+ name = "invoice_signers"
85
+ queryset = Person.objects.all()
86
+ default = None
87
+ verbose_name = "Invoice Signers"
88
+
89
+
90
+ @global_preferences_registry.register
91
+ class InvoiceCompanyPreference(IntegerPreference):
92
+ section = accounting_section
93
+ name = "invoice_company"
94
+ default = 0
95
+
96
+ verbose_name = "Invoice Company"
97
+ help_text = "The PK of the company who issues the invoices"
98
+
99
+
100
+ @global_preferences_registry.register
101
+ class DefaultFromEmailAddressPreference(StringPreference):
102
+ section = accounting_section
103
+ name = "default_from_email_address"
104
+ default = settings.DEFAULT_FROM_EMAIL
105
+
106
+ verbose_name = "The default from email address"
107
+ help_text = "The default from email address used to send invoice"
@@ -0,0 +1,10 @@
1
+ from .booking_entry import BookingEntryFactory
2
+ from .entry_accounting_information import (
3
+ CompanyAccountingFactory,
4
+ EntryAccountingInformationFactory,
5
+ )
6
+ from .invoice import (
7
+ InvoiceFactory,
8
+ InvoiceTypeFactory,
9
+ )
10
+ from .transactions import TransactionFactory, LocalCurrencyTransactionFactory
@@ -0,0 +1,21 @@
1
+ import factory
2
+ from factory.fuzzy import FuzzyDecimal
3
+ from wbaccounting.models import BookingEntry
4
+
5
+
6
+ class BookingEntryFactory(factory.django.DjangoModelFactory):
7
+ class Meta: # type: ignore
8
+ model = BookingEntry
9
+
10
+ # resolved
11
+ title = factory.Faker("text", max_nb_chars=64)
12
+ booking_date = factory.Faker("date_between", start_date="+2d", end_date="+3d")
13
+ payment_date = factory.Faker("date_object")
14
+ reference_date = factory.Faker("date_object")
15
+ gross_value = factory.Faker("pydecimal", right_digits=4, min_value=0, max_value=99999999999)
16
+ net_value = factory.Faker("pydecimal", right_digits=4, min_value=0, max_value=99999999999)
17
+ vat = FuzzyDecimal(0, 0.9, 4)
18
+ currency = factory.SelfAttribute("invoice.invoice_currency")
19
+
20
+ invoice = factory.SubFactory("wbaccounting.factories.InvoiceFactory")
21
+ counterparty = factory.SubFactory("wbcore.contrib.directory.factories.EntryFactory")
@@ -0,0 +1,46 @@
1
+ import factory
2
+ from factory.fuzzy import FuzzyDecimal
3
+ from wbaccounting.models import EntryAccountingInformation
4
+ from wbcore.contrib.directory.factories import CompanyFactory, EmailContactFactory
5
+
6
+
7
+ class EntryAccountingInformationFactory(factory.django.DjangoModelFactory):
8
+ class Meta: # type: ignore
9
+ model = EntryAccountingInformation
10
+
11
+ entry = factory.SubFactory("wbcore.contrib.directory.factories.EntryFactory")
12
+ tax_id = factory.Faker("text", max_nb_chars=64)
13
+ vat = FuzzyDecimal(0, 0.9, 4)
14
+ send_mail = factory.Faker("pybool")
15
+ counterparty_is_private = False
16
+
17
+ email_body = factory.Faker("paragraph")
18
+
19
+ @factory.post_generation
20
+ def post(self, create, extracted, **kwargs):
21
+ if isinstance(self, EntryAccountingInformationFactory) and not create:
22
+ self.email_to.add(EmailContactFactory.create())
23
+ self.email_cc_add(EmailContactFactory.create())
24
+ self.email_bcc.add(EmailContactFactory.create())
25
+
26
+ if isinstance(self, dict):
27
+ self["email_to"] = [EmailContactFactory.create().id]
28
+ self["email_cc"] = [EmailContactFactory.create().id]
29
+ self["email_bcc"] = [EmailContactFactory.create().id]
30
+
31
+ @factory.post_generation
32
+ def exempt_users(self, create, extracted, **kwargs):
33
+ if not create:
34
+ return
35
+
36
+ if extracted:
37
+ for user in extracted:
38
+ self.exempt_users.add(user)
39
+
40
+ default_currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyFactory")
41
+
42
+
43
+ class CompanyAccountingFactory(CompanyFactory):
44
+ entry_accounting_information = factory.RelatedFactory(
45
+ "wbaccounting.factories.EntryAccountingInformationFactory", "entry"
46
+ )
@@ -0,0 +1,43 @@
1
+ import factory
2
+ from wbaccounting.models import Invoice, InvoiceType
3
+
4
+
5
+ class InvoiceFactory(factory.django.DjangoModelFactory):
6
+ class Meta: # type: ignore
7
+ model = Invoice
8
+
9
+ title = factory.Faker("text", max_nb_chars=64)
10
+ invoice_date = factory.Faker("date_object")
11
+ reference_date = factory.Faker("date_object")
12
+ invoice_currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyUSDFactory")
13
+
14
+ counterparty = factory.SubFactory("wbcore.contrib.directory.factories.EntryFactory")
15
+ invoice_type = factory.SubFactory("wbaccounting.factories.InvoiceTypeFactory")
16
+
17
+ text_above = factory.Faker("text")
18
+ text_below = factory.Faker("text")
19
+
20
+ # @factory.post_generation
21
+ # def invoice_document(self, create, extracted, **kwargs):
22
+ # self.refresh_invoice_document(override_status=True)
23
+
24
+ # is_counterparty_invoice
25
+
26
+ # @classmethod
27
+ # def _create(cls, model_class, *args, **kwargs):
28
+ # company = CompanyFactory()
29
+ # signee = PersonSignatureFactory()
30
+ # global_preferences_registry.manager()["wbaccounting__invoice_company"] = company.id
31
+ # global_preferences_registry.manager()["wbaccounting__invoice_signers"] = Person.objects.filter(id=signee.id)
32
+ # """Override the default ``_create`` with our custom call."""
33
+ # manager = cls._get_manager(model_class)
34
+ # # The default would use ``manager.create(*args, **kwargs)``
35
+ # return manager.create(*args, **kwargs)
36
+
37
+
38
+ class InvoiceTypeFactory(factory.django.DjangoModelFactory):
39
+ name = factory.Sequence(lambda n: f"Invoice Type {n}")
40
+ processor = factory.Faker("text", max_nb_chars=64)
41
+
42
+ class Meta: # type: ignore
43
+ model = InvoiceType
@@ -0,0 +1,32 @@
1
+ from decimal import Decimal
2
+
3
+ import factory
4
+ from wbaccounting.models import Transaction
5
+
6
+
7
+ class AbstractTransactionFactory(factory.django.DjangoModelFactory):
8
+ class Meta:
9
+ model = Transaction
10
+ abstract = True
11
+
12
+ booking_date = factory.Faker("date_between", start_date="+2d", end_date="+3d")
13
+ value_date = factory.Faker("date_object")
14
+
15
+ bank_account = factory.SubFactory("wbcore.contrib.directory.factories.BankingContactFactory")
16
+ from_bank_account = factory.SubFactory("wbcore.contrib.directory.factories.BankingContactFactory")
17
+ to_bank_account = factory.SubFactory("wbcore.contrib.directory.factories.BankingContactFactory")
18
+
19
+ @factory.post_generation
20
+ def set_currency(self, create, extracted, **kwargs):
21
+ if isinstance(self, dict):
22
+ self["currency"] = self["bank_account"].currency
23
+ else:
24
+ self.currency = self.bank_account.currency
25
+
26
+
27
+ class TransactionFactory(AbstractTransactionFactory):
28
+ value = factory.Faker("pydecimal", min_value=Decimal(0.1), max_value=Decimal(10000000))
29
+
30
+
31
+ class LocalCurrencyTransactionFactory(AbstractTransactionFactory):
32
+ value_local_ccy = factory.Faker("pydecimal", min_value=Decimal(0.1), max_value=Decimal(10000000))
File without changes