wbaccounting 2.2.1__py2.py3-none-any.whl
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.
- wbaccounting/__init__.py +1 -0
- wbaccounting/admin/__init__.py +5 -0
- wbaccounting/admin/booking_entry.py +53 -0
- wbaccounting/admin/entry_accounting_information.py +10 -0
- wbaccounting/admin/invoice.py +26 -0
- wbaccounting/admin/invoice_type.py +8 -0
- wbaccounting/admin/transactions.py +16 -0
- wbaccounting/apps.py +5 -0
- wbaccounting/dynamic_preferences_registry.py +107 -0
- wbaccounting/factories/__init__.py +10 -0
- wbaccounting/factories/booking_entry.py +21 -0
- wbaccounting/factories/entry_accounting_information.py +46 -0
- wbaccounting/factories/invoice.py +43 -0
- wbaccounting/factories/transactions.py +32 -0
- wbaccounting/files/__init__.py +0 -0
- wbaccounting/files/invoice_document_file.py +134 -0
- wbaccounting/files/utils.py +331 -0
- wbaccounting/generators/__init__.py +6 -0
- wbaccounting/generators/base.py +120 -0
- wbaccounting/io/handlers/__init__.py +0 -0
- wbaccounting/io/handlers/transactions.py +32 -0
- wbaccounting/io/parsers/__init__.py +0 -0
- wbaccounting/io/parsers/societe_generale_lux.py +49 -0
- wbaccounting/io/parsers/societe_generale_lux_prenotification.py +60 -0
- wbaccounting/migrations/0001_initial_squashed_squashed_0005_alter_bookingentry_counterparty_and_more.py +284 -0
- wbaccounting/migrations/0006_alter_invoice_status.py +30 -0
- wbaccounting/migrations/0007_alter_invoice_options.py +23 -0
- wbaccounting/migrations/0008_alter_invoice_options.py +20 -0
- wbaccounting/migrations/0009_invoicetype_alter_bookingentry_options_and_more.py +366 -0
- wbaccounting/migrations/0010_alter_bookingentry_options.py +20 -0
- wbaccounting/migrations/0011_transaction.py +103 -0
- wbaccounting/migrations/0012_entryaccountinginformation_external_invoice_users.py +25 -0
- wbaccounting/migrations/__init__.py +0 -0
- wbaccounting/models/__init__.py +6 -0
- wbaccounting/models/booking_entry.py +167 -0
- wbaccounting/models/entry_accounting_information.py +157 -0
- wbaccounting/models/invoice.py +467 -0
- wbaccounting/models/invoice_type.py +30 -0
- wbaccounting/models/model_tasks.py +71 -0
- wbaccounting/models/transactions.py +112 -0
- wbaccounting/permissions.py +6 -0
- wbaccounting/processors/__init__.py +0 -0
- wbaccounting/processors/dummy_processor.py +5 -0
- wbaccounting/serializers/__init__.py +12 -0
- wbaccounting/serializers/booking_entry.py +78 -0
- wbaccounting/serializers/consolidated_invoice.py +109 -0
- wbaccounting/serializers/entry_accounting_information.py +149 -0
- wbaccounting/serializers/invoice.py +95 -0
- wbaccounting/serializers/invoice_type.py +16 -0
- wbaccounting/serializers/transactions.py +50 -0
- wbaccounting/tests/__init__.py +0 -0
- wbaccounting/tests/conftest.py +65 -0
- wbaccounting/tests/test_displays/__init__.py +0 -0
- wbaccounting/tests/test_displays/test_booking_entries.py +1 -0
- wbaccounting/tests/test_models/__init__.py +0 -0
- wbaccounting/tests/test_models/test_booking_entries.py +119 -0
- wbaccounting/tests/test_models/test_entry_accounting_information.py +81 -0
- wbaccounting/tests/test_models/test_invoice_types.py +21 -0
- wbaccounting/tests/test_models/test_invoices.py +73 -0
- wbaccounting/tests/test_models/test_transactions.py +40 -0
- wbaccounting/tests/test_processors.py +28 -0
- wbaccounting/tests/test_serializers/__init__.py +0 -0
- wbaccounting/tests/test_serializers/test_booking_entries.py +69 -0
- wbaccounting/tests/test_serializers/test_entry_accounting_information.py +64 -0
- wbaccounting/tests/test_serializers/test_invoice_types.py +35 -0
- wbaccounting/tests/test_serializers/test_transactions.py +72 -0
- wbaccounting/urls.py +68 -0
- wbaccounting/viewsets/__init__.py +12 -0
- wbaccounting/viewsets/booking_entry.py +61 -0
- wbaccounting/viewsets/buttons/__init__.py +3 -0
- wbaccounting/viewsets/buttons/booking_entry.py +15 -0
- wbaccounting/viewsets/buttons/entry_accounting_information.py +100 -0
- wbaccounting/viewsets/buttons/invoice.py +65 -0
- wbaccounting/viewsets/cashflows.py +124 -0
- wbaccounting/viewsets/display/__init__.py +8 -0
- wbaccounting/viewsets/display/booking_entry.py +58 -0
- wbaccounting/viewsets/display/cashflows.py +58 -0
- wbaccounting/viewsets/display/entry_accounting_information.py +91 -0
- wbaccounting/viewsets/display/invoice.py +218 -0
- wbaccounting/viewsets/display/invoice_type.py +19 -0
- wbaccounting/viewsets/display/transactions.py +35 -0
- wbaccounting/viewsets/endpoints/__init__.py +1 -0
- wbaccounting/viewsets/endpoints/invoice.py +6 -0
- wbaccounting/viewsets/entry_accounting_information.py +143 -0
- wbaccounting/viewsets/invoice.py +277 -0
- wbaccounting/viewsets/invoice_type.py +25 -0
- wbaccounting/viewsets/menu/__init__.py +6 -0
- wbaccounting/viewsets/menu/booking_entry.py +15 -0
- wbaccounting/viewsets/menu/cashflows.py +10 -0
- wbaccounting/viewsets/menu/entry_accounting_information.py +11 -0
- wbaccounting/viewsets/menu/invoice.py +15 -0
- wbaccounting/viewsets/menu/invoice_type.py +15 -0
- wbaccounting/viewsets/menu/transactions.py +15 -0
- wbaccounting/viewsets/titles/__init__.py +4 -0
- wbaccounting/viewsets/titles/booking_entry.py +12 -0
- wbaccounting/viewsets/titles/entry_accounting_information.py +12 -0
- wbaccounting/viewsets/titles/invoice.py +23 -0
- wbaccounting/viewsets/titles/invoice_type.py +12 -0
- wbaccounting/viewsets/transactions.py +34 -0
- wbaccounting-2.2.1.dist-info/METADATA +8 -0
- wbaccounting-2.2.1.dist-info/RECORD +102 -0
- wbaccounting-2.2.1.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from wbcore.metadata.configs import display as dp
|
|
4
|
+
from wbcore.metadata.configs.display.instance_display.shortcuts import Display, default
|
|
5
|
+
from wbcore.metadata.configs.display.instance_display.utils import repeat_field
|
|
6
|
+
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EntryAccountingInformationDisplayConfig(DisplayViewConfig):
|
|
10
|
+
def get_list_display(self) -> Optional[dp.ListDisplay]:
|
|
11
|
+
return dp.ListDisplay(
|
|
12
|
+
fields=[
|
|
13
|
+
dp.Field(key="entry", label="CRM", width=400),
|
|
14
|
+
dp.Field(key="tax_id", label="Tax ID"),
|
|
15
|
+
dp.Field(key="vat", label="VAT", width=100),
|
|
16
|
+
dp.Field(key="default_currency", label="Currency", width=100),
|
|
17
|
+
dp.Field(key="send_mail", label="Send Mail", width=100),
|
|
18
|
+
],
|
|
19
|
+
formatting=[
|
|
20
|
+
dp.Formatting(
|
|
21
|
+
column="counterparty_is_private",
|
|
22
|
+
formatting_rules=[dp.FormattingRule(condition=("==", True), style={"backgroundColor": "#708090"})],
|
|
23
|
+
)
|
|
24
|
+
],
|
|
25
|
+
legends=[
|
|
26
|
+
dp.Legend(
|
|
27
|
+
key="counterparty_is_private",
|
|
28
|
+
items=[dp.LegendItem(icon="#708090", label="Private Counterparty", value=True)],
|
|
29
|
+
)
|
|
30
|
+
],
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def get_instance_display(self) -> Display:
|
|
34
|
+
return dp.Display(
|
|
35
|
+
pages=[
|
|
36
|
+
dp.Page(
|
|
37
|
+
title="General Information",
|
|
38
|
+
layouts={
|
|
39
|
+
default(): dp.Layout(
|
|
40
|
+
grid_template_areas=[
|
|
41
|
+
["entry", "booking_entry_generator"],
|
|
42
|
+
["counterparty_is_private", "exempt_users"],
|
|
43
|
+
["default_currency", "tax_id"],
|
|
44
|
+
["vat", "default_invoice_type"],
|
|
45
|
+
["external_invoice_users", "."],
|
|
46
|
+
],
|
|
47
|
+
)
|
|
48
|
+
},
|
|
49
|
+
),
|
|
50
|
+
dp.Page(
|
|
51
|
+
title="E-Mail Settings",
|
|
52
|
+
layouts={
|
|
53
|
+
dp.default(): dp.Layout(
|
|
54
|
+
grid_template_areas=[
|
|
55
|
+
["send_mail", "."],
|
|
56
|
+
["email_to", "."],
|
|
57
|
+
["email_cc", "."],
|
|
58
|
+
["email_bcc", "."],
|
|
59
|
+
["email_subject", "."],
|
|
60
|
+
[repeat_field(2, "email_body")],
|
|
61
|
+
],
|
|
62
|
+
grid_template_columns=["600px", "1fr"],
|
|
63
|
+
)
|
|
64
|
+
},
|
|
65
|
+
),
|
|
66
|
+
dp.Page(
|
|
67
|
+
title="Invoices",
|
|
68
|
+
layouts={
|
|
69
|
+
default(): dp.Layout(
|
|
70
|
+
grid_template_areas=[
|
|
71
|
+
["invoices"],
|
|
72
|
+
],
|
|
73
|
+
grid_template_rows=["600px"],
|
|
74
|
+
inlines=[dp.Inline(key="invoices", endpoint="invoices")],
|
|
75
|
+
)
|
|
76
|
+
},
|
|
77
|
+
),
|
|
78
|
+
dp.Page(
|
|
79
|
+
title="Bookings",
|
|
80
|
+
layouts={
|
|
81
|
+
default(): dp.Layout(
|
|
82
|
+
grid_template_areas=[
|
|
83
|
+
["bookingentries"],
|
|
84
|
+
],
|
|
85
|
+
grid_template_rows=["600px"],
|
|
86
|
+
inlines=[dp.Inline(key="bookingentries", endpoint="bookingentries")],
|
|
87
|
+
)
|
|
88
|
+
},
|
|
89
|
+
),
|
|
90
|
+
]
|
|
91
|
+
)
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from rest_framework.reverse import reverse
|
|
4
|
+
from wbaccounting.models import Invoice
|
|
5
|
+
from wbcore.contrib.color.enums import WBColor
|
|
6
|
+
from wbcore.metadata.configs import display as dp
|
|
7
|
+
from wbcore.metadata.configs.display.instance_display.shortcuts import (
|
|
8
|
+
Display,
|
|
9
|
+
create_simple_display,
|
|
10
|
+
create_simple_section,
|
|
11
|
+
)
|
|
12
|
+
from wbcore.metadata.configs.display.instance_display.utils import repeat_field
|
|
13
|
+
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
14
|
+
|
|
15
|
+
COLOR_DRAFT = "rgb(255,249,196)"
|
|
16
|
+
COLOR_SUBMITTED = "rgb(51, 204, 255)"
|
|
17
|
+
COLOR_SENT = "rgb(255, 153, 102)"
|
|
18
|
+
COLOR_PAID = "rgb(214, 229, 145)"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class InvoiceDisplayConfig(DisplayViewConfig):
|
|
22
|
+
def get_list_display(self) -> Optional[dp.ListDisplay]:
|
|
23
|
+
return dp.ListDisplay(
|
|
24
|
+
fields=[
|
|
25
|
+
dp.Field(key="status", label="Status"),
|
|
26
|
+
dp.Field(key="type", label="Type"),
|
|
27
|
+
dp.Field(key="counterparty", label="Counterparty"),
|
|
28
|
+
dp.Field(key="title", label="Title"),
|
|
29
|
+
dp.Field(key="invoice_date", label="Invoice Date"),
|
|
30
|
+
dp.Field(key="reference_date", label="Reference Date"),
|
|
31
|
+
dp.Field(key="gross_value", label="Gross Value"),
|
|
32
|
+
dp.Field(key="net_value", label="Net Value"),
|
|
33
|
+
],
|
|
34
|
+
legends=[
|
|
35
|
+
dp.Legend(
|
|
36
|
+
key="status",
|
|
37
|
+
items=[
|
|
38
|
+
dp.LegendItem(
|
|
39
|
+
icon=COLOR_DRAFT,
|
|
40
|
+
label=Invoice.Status.DRAFT.label,
|
|
41
|
+
value=Invoice.Status.DRAFT.name,
|
|
42
|
+
),
|
|
43
|
+
dp.LegendItem(
|
|
44
|
+
icon=COLOR_SUBMITTED,
|
|
45
|
+
label=Invoice.Status.SUBMITTED.label,
|
|
46
|
+
value=Invoice.Status.SUBMITTED.name,
|
|
47
|
+
),
|
|
48
|
+
dp.LegendItem(
|
|
49
|
+
icon=WBColor.BLUE_LIGHT.value,
|
|
50
|
+
label=Invoice.Status.APPROVED.label,
|
|
51
|
+
value=Invoice.Status.APPROVED.name,
|
|
52
|
+
),
|
|
53
|
+
dp.LegendItem(
|
|
54
|
+
icon=COLOR_SENT,
|
|
55
|
+
label=Invoice.Status.SENT.label,
|
|
56
|
+
value=Invoice.Status.SENT.name,
|
|
57
|
+
),
|
|
58
|
+
dp.LegendItem(
|
|
59
|
+
icon=WBColor.GREEN_LIGHT.value,
|
|
60
|
+
label=Invoice.Status.PAID.label,
|
|
61
|
+
value=Invoice.Status.PAID.name,
|
|
62
|
+
),
|
|
63
|
+
dp.LegendItem(
|
|
64
|
+
icon=WBColor.GREY.value,
|
|
65
|
+
label=Invoice.Status.CANCELLED.label,
|
|
66
|
+
value=Invoice.Status.CANCELLED.name,
|
|
67
|
+
),
|
|
68
|
+
],
|
|
69
|
+
)
|
|
70
|
+
],
|
|
71
|
+
formatting=[
|
|
72
|
+
dp.Formatting(
|
|
73
|
+
column="status",
|
|
74
|
+
formatting_rules=[
|
|
75
|
+
dp.FormattingRule(
|
|
76
|
+
style={"backgroundColor": COLOR_DRAFT},
|
|
77
|
+
condition=("==", Invoice.Status.DRAFT.name),
|
|
78
|
+
),
|
|
79
|
+
dp.FormattingRule(
|
|
80
|
+
style={"backgroundColor": COLOR_SUBMITTED},
|
|
81
|
+
condition=("==", Invoice.Status.SUBMITTED.name),
|
|
82
|
+
),
|
|
83
|
+
dp.FormattingRule(
|
|
84
|
+
style={"backgroundColor": WBColor.BLUE_LIGHT.value},
|
|
85
|
+
condition=("==", Invoice.Status.APPROVED.name),
|
|
86
|
+
),
|
|
87
|
+
dp.FormattingRule(
|
|
88
|
+
style={"backgroundColor": COLOR_SENT},
|
|
89
|
+
condition=("==", Invoice.Status.SENT.name),
|
|
90
|
+
),
|
|
91
|
+
dp.FormattingRule(
|
|
92
|
+
style={"backgroundColor": WBColor.GREEN_LIGHT.value},
|
|
93
|
+
condition=("==", Invoice.Status.PAID.name),
|
|
94
|
+
),
|
|
95
|
+
dp.FormattingRule(
|
|
96
|
+
style={"backgroundColor": WBColor.GREY.value},
|
|
97
|
+
condition=("==", Invoice.Status.CANCELLED.name),
|
|
98
|
+
),
|
|
99
|
+
],
|
|
100
|
+
),
|
|
101
|
+
],
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def get_instance_display(self) -> Display:
|
|
105
|
+
return create_simple_display(
|
|
106
|
+
[
|
|
107
|
+
[repeat_field(2, "status")],
|
|
108
|
+
["title", "invoice_type"],
|
|
109
|
+
["counterparty", "reference_date"],
|
|
110
|
+
["invoice_date", "invoice_currency"],
|
|
111
|
+
["text_above", "text_below"],
|
|
112
|
+
[repeat_field(2, "booking_entry_section")],
|
|
113
|
+
],
|
|
114
|
+
[
|
|
115
|
+
create_simple_section(
|
|
116
|
+
"booking_entry_section", "Booking Entries", [["bookingentries"]], "bookingentries", collapsed=True
|
|
117
|
+
)
|
|
118
|
+
],
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class ConsolidatedInvoiceDisplayConfig(DisplayViewConfig):
|
|
123
|
+
def get_list_display(self) -> dp.ListDisplay:
|
|
124
|
+
return dp.ListDisplay(
|
|
125
|
+
fields=[
|
|
126
|
+
dp.Field(key="value", label="Value"),
|
|
127
|
+
],
|
|
128
|
+
tree=True,
|
|
129
|
+
tree_group_pinned="left",
|
|
130
|
+
tree_group_field="group",
|
|
131
|
+
tree_group_label="Group",
|
|
132
|
+
tree_group_level_options=[
|
|
133
|
+
dp.TreeGroupLevelOption(
|
|
134
|
+
filter_key="lookup",
|
|
135
|
+
list_endpoint=reverse(
|
|
136
|
+
"wbaccounting:consolidated-invoice-list",
|
|
137
|
+
args=[],
|
|
138
|
+
request=self.request,
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
],
|
|
142
|
+
legends=[
|
|
143
|
+
dp.Legend(
|
|
144
|
+
key="status",
|
|
145
|
+
label="Lowest Status",
|
|
146
|
+
items=[
|
|
147
|
+
dp.LegendItem(
|
|
148
|
+
icon=COLOR_DRAFT,
|
|
149
|
+
label=Invoice.Status.DRAFT.label,
|
|
150
|
+
value=Invoice.Status.DRAFT.name,
|
|
151
|
+
),
|
|
152
|
+
dp.LegendItem(
|
|
153
|
+
icon=COLOR_SUBMITTED,
|
|
154
|
+
label=Invoice.Status.SUBMITTED.label,
|
|
155
|
+
value=Invoice.Status.SUBMITTED.name,
|
|
156
|
+
),
|
|
157
|
+
dp.LegendItem(
|
|
158
|
+
icon=WBColor.BLUE_LIGHT.value,
|
|
159
|
+
label=Invoice.Status.APPROVED.label,
|
|
160
|
+
value=Invoice.Status.APPROVED.name,
|
|
161
|
+
),
|
|
162
|
+
dp.LegendItem(
|
|
163
|
+
icon=COLOR_SENT,
|
|
164
|
+
label=Invoice.Status.SENT.label,
|
|
165
|
+
value=Invoice.Status.SENT.name,
|
|
166
|
+
),
|
|
167
|
+
dp.LegendItem(
|
|
168
|
+
icon=WBColor.GREEN_LIGHT.value,
|
|
169
|
+
label=Invoice.Status.PAID.label,
|
|
170
|
+
value=Invoice.Status.PAID.name,
|
|
171
|
+
),
|
|
172
|
+
dp.LegendItem(
|
|
173
|
+
icon=WBColor.GREY.value,
|
|
174
|
+
label=Invoice.Status.CANCELLED.label,
|
|
175
|
+
value=Invoice.Status.CANCELLED.name,
|
|
176
|
+
),
|
|
177
|
+
],
|
|
178
|
+
),
|
|
179
|
+
],
|
|
180
|
+
formatting=[
|
|
181
|
+
dp.Formatting(
|
|
182
|
+
column="num_paid",
|
|
183
|
+
formatting_rules=[
|
|
184
|
+
dp.FormattingRule(
|
|
185
|
+
style={"backgroundColor": COLOR_PAID},
|
|
186
|
+
condition=(">", 0),
|
|
187
|
+
)
|
|
188
|
+
],
|
|
189
|
+
),
|
|
190
|
+
dp.Formatting(
|
|
191
|
+
column="num_sent",
|
|
192
|
+
formatting_rules=[
|
|
193
|
+
dp.FormattingRule(
|
|
194
|
+
style={"backgroundColor": COLOR_SENT},
|
|
195
|
+
condition=(">", 0),
|
|
196
|
+
)
|
|
197
|
+
],
|
|
198
|
+
),
|
|
199
|
+
dp.Formatting(
|
|
200
|
+
column="num_submitted",
|
|
201
|
+
formatting_rules=[
|
|
202
|
+
dp.FormattingRule(
|
|
203
|
+
style={"backgroundColor": COLOR_SUBMITTED},
|
|
204
|
+
condition=(">", 0),
|
|
205
|
+
)
|
|
206
|
+
],
|
|
207
|
+
),
|
|
208
|
+
dp.Formatting(
|
|
209
|
+
column="num_draft",
|
|
210
|
+
formatting_rules=[
|
|
211
|
+
dp.FormattingRule(
|
|
212
|
+
style={"backgroundColor": COLOR_DRAFT},
|
|
213
|
+
condition=(">", 0),
|
|
214
|
+
)
|
|
215
|
+
],
|
|
216
|
+
),
|
|
217
|
+
],
|
|
218
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from wbcore.metadata.configs import display as dp
|
|
2
|
+
from wbcore.metadata.configs.display.instance_display.shortcuts import (
|
|
3
|
+
Display,
|
|
4
|
+
create_simple_display,
|
|
5
|
+
)
|
|
6
|
+
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class InvoiceTypeDisplayConfig(DisplayViewConfig):
|
|
10
|
+
def get_list_display(self) -> dp.ListDisplay:
|
|
11
|
+
return dp.ListDisplay(
|
|
12
|
+
fields=[
|
|
13
|
+
dp.Field(key="name", label="Name"),
|
|
14
|
+
dp.Field(key="processor", label="Processor"),
|
|
15
|
+
]
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def get_instance_display(self) -> Display:
|
|
19
|
+
return create_simple_display([["name", "processor"]])
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from django.utils.translation import gettext as _
|
|
2
|
+
from wbcore.metadata.configs import display as dp
|
|
3
|
+
from wbcore.metadata.configs.display.instance_display.shortcuts import (
|
|
4
|
+
Display,
|
|
5
|
+
create_simple_display,
|
|
6
|
+
)
|
|
7
|
+
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TransactionDisplayConfig(DisplayViewConfig):
|
|
11
|
+
def get_list_display(self) -> dp.ListDisplay:
|
|
12
|
+
return dp.ListDisplay(
|
|
13
|
+
fields=[
|
|
14
|
+
dp.Field(key="booking_date", label=_("Booking Date"), width=150),
|
|
15
|
+
dp.Field(key="value_date", label=_("Value Date"), width=150),
|
|
16
|
+
dp.Field(key="bank_account", label=_("Bank Account"), width=450),
|
|
17
|
+
# dp.Field(key="from_bank_account", label=_("Source"), width=300),
|
|
18
|
+
# dp.Field(key="to_bank_account", label=_("Target"), width=300),
|
|
19
|
+
dp.Field(key="value_local_ccy", label=_("Value (Local)"), width=150),
|
|
20
|
+
dp.Field(key="value", label=_("Value"), width=150),
|
|
21
|
+
dp.Field(key="description", label=_("Description"), width=450),
|
|
22
|
+
]
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def get_instance_display(self) -> Display:
|
|
26
|
+
return create_simple_display(
|
|
27
|
+
[
|
|
28
|
+
["booking_date", "value_date"],
|
|
29
|
+
["bank_account", "."],
|
|
30
|
+
["from_bank_account", "to_bank_account"],
|
|
31
|
+
["value", "currency"],
|
|
32
|
+
["value_local_ccy", "fx_rate"],
|
|
33
|
+
["description", "description"],
|
|
34
|
+
]
|
|
35
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .invoice import ConsolidatedInvoiceEndpointConfig
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
|
|
3
|
+
from django.db.models import Exists, OuterRef, QuerySet
|
|
4
|
+
from rest_framework import status
|
|
5
|
+
from rest_framework.decorators import action
|
|
6
|
+
from rest_framework.permissions import IsAuthenticated
|
|
7
|
+
from rest_framework.response import Response
|
|
8
|
+
from wbaccounting.models import EntryAccountingInformation, Invoice
|
|
9
|
+
from wbaccounting.models.booking_entry import BookingEntry
|
|
10
|
+
from wbaccounting.serializers import (
|
|
11
|
+
EntryAccountingInformationModelSerializer,
|
|
12
|
+
EntryAccountingInformationRepresentationSerializer,
|
|
13
|
+
)
|
|
14
|
+
from wbaccounting.viewsets.buttons import EntryAccountingInformationButtonConfig
|
|
15
|
+
from wbaccounting.viewsets.display import EntryAccountingInformationDisplayConfig
|
|
16
|
+
from wbaccounting.viewsets.titles import EntryAccountingInformationTitleConfig
|
|
17
|
+
from wbcore import viewsets
|
|
18
|
+
from wbcore.utils.date import get_date_interval_from_request
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class EntryAccountingInformationRepresentationViewSet(viewsets.RepresentationViewSet):
|
|
22
|
+
search_fields = ("entry__computed_str",)
|
|
23
|
+
queryset = EntryAccountingInformation.objects.all()
|
|
24
|
+
serializer_class = EntryAccountingInformationRepresentationSerializer
|
|
25
|
+
|
|
26
|
+
def get_queryset(self):
|
|
27
|
+
return EntryAccountingInformation.objects.filter_for_user(self.request.user)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class EntryAccountingInformationModelViewSet(viewsets.ModelViewSet):
|
|
31
|
+
IDENTIFIER = "wbaccounting:entryaccountinginformation"
|
|
32
|
+
filterset_fields = {
|
|
33
|
+
"entry": ["exact"],
|
|
34
|
+
"tax_id": ["exact", "icontains"],
|
|
35
|
+
"vat": ["gte", "exact", "lte"],
|
|
36
|
+
"default_currency": ["gte", "exact", "lte"],
|
|
37
|
+
"send_mail": ["exact"],
|
|
38
|
+
"counterparty_is_private": ["exact"],
|
|
39
|
+
"exempt_users": ["exact"],
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
serializer_class = EntryAccountingInformationModelSerializer
|
|
43
|
+
queryset = EntryAccountingInformation.objects.all()
|
|
44
|
+
|
|
45
|
+
search_fields = ["entry__computed_str"]
|
|
46
|
+
ordering_fields = ["tax_id", "vat", "send_mail", "counterparty_is_private"]
|
|
47
|
+
ordering = ["id"]
|
|
48
|
+
|
|
49
|
+
display_config_class = EntryAccountingInformationDisplayConfig
|
|
50
|
+
title_config_class = EntryAccountingInformationTitleConfig
|
|
51
|
+
button_config_class = EntryAccountingInformationButtonConfig
|
|
52
|
+
|
|
53
|
+
def get_queryset(self) -> QuerySet[EntryAccountingInformation]:
|
|
54
|
+
return (
|
|
55
|
+
EntryAccountingInformation.objects.filter_for_user(self.request.user)
|
|
56
|
+
.select_related(
|
|
57
|
+
"entry",
|
|
58
|
+
"default_currency",
|
|
59
|
+
"default_invoice_type",
|
|
60
|
+
)
|
|
61
|
+
.prefetch_related(
|
|
62
|
+
"exempt_users",
|
|
63
|
+
"email_to",
|
|
64
|
+
"email_cc",
|
|
65
|
+
"email_bcc",
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@action(detail=True, methods=["POST"], permission_classes=[IsAuthenticated])
|
|
70
|
+
def generate_booking_entries(self, request, pk):
|
|
71
|
+
if (
|
|
72
|
+
(user := request.user)
|
|
73
|
+
and (user.is_superuser or user.has_perm("wbaccounting.can_generate_booking_entries"))
|
|
74
|
+
and (eai := self.get_object())
|
|
75
|
+
and eai is not None
|
|
76
|
+
):
|
|
77
|
+
start, end = get_date_interval_from_request(request, request_type="POST")
|
|
78
|
+
eai.generate_booking_entries(start, end) # type: ignore
|
|
79
|
+
return Response(
|
|
80
|
+
{"__notification": {"title": "Booking Entries are being generated in the background."}},
|
|
81
|
+
status=status.HTTP_200_OK,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
@action(detail=False, methods=["POST"], permission_classes=[IsAuthenticated])
|
|
85
|
+
def generate_booking_entries_for_counterparties(self, request, pk=None):
|
|
86
|
+
eais = EntryAccountingInformation.objects.filter(entry__id__in=request.POST.get("counterparties").split(","))
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
(user := request.user)
|
|
90
|
+
and (user.is_superuser or user.has_perm("wbaccounting.can_generate_booking_entries"))
|
|
91
|
+
and eais.exists()
|
|
92
|
+
):
|
|
93
|
+
for eai in eais:
|
|
94
|
+
start, end = get_date_interval_from_request(request, request_type="POST")
|
|
95
|
+
eai.generate_booking_entries(start, end) # type: ignore
|
|
96
|
+
return Response(
|
|
97
|
+
{"__notification": {"title": "Booking Entries are being generated in the background."}},
|
|
98
|
+
status=status.HTTP_200_OK,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@action(detail=False, methods=["POST"], permission_classes=[IsAuthenticated])
|
|
102
|
+
def generate_invoices_for_counterparties(self, request, pk=None):
|
|
103
|
+
try:
|
|
104
|
+
eais = EntryAccountingInformation.objects.filter(
|
|
105
|
+
entry__id__in=request.POST.get("counterparties").split(",")
|
|
106
|
+
)
|
|
107
|
+
except AttributeError:
|
|
108
|
+
eais = EntryAccountingInformation.objects.all()
|
|
109
|
+
|
|
110
|
+
if (
|
|
111
|
+
(user := request.user)
|
|
112
|
+
and (user.is_superuser or user.has_perm("wbaccounting.can_generate_invoice"))
|
|
113
|
+
and eais.exists()
|
|
114
|
+
):
|
|
115
|
+
eais = eais.annotate(
|
|
116
|
+
has_open_bookings=Exists(
|
|
117
|
+
BookingEntry.objects.filter(
|
|
118
|
+
counterparty=OuterRef("entry"),
|
|
119
|
+
invoice__isnull=True,
|
|
120
|
+
payment_date__isnull=True,
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
).filter(has_open_bookings=True)
|
|
124
|
+
for eai in eais:
|
|
125
|
+
Invoice.objects.create_for_counterparty(eai.entry, invoice_date=date.today())
|
|
126
|
+
return Response(
|
|
127
|
+
{"__notification": {"title": "Invoices are being generated in the background."}},
|
|
128
|
+
status=status.HTTP_200_OK,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
@action(detail=True, methods=["POST"], permission_classes=[IsAuthenticated])
|
|
132
|
+
def invoice_booking_entries(self, request, pk):
|
|
133
|
+
if (
|
|
134
|
+
(user := request.user)
|
|
135
|
+
and (user.is_superuser or user.has_perm("wbaccounting.can_generate_invoice"))
|
|
136
|
+
and (eai := self.get_object())
|
|
137
|
+
and eai is not None
|
|
138
|
+
):
|
|
139
|
+
Invoice.objects.create_for_counterparty(eai.entry, invoice_date=date.today())
|
|
140
|
+
return Response(
|
|
141
|
+
{"__notification": {"title": "Booking Entries are being generated in the background."}},
|
|
142
|
+
status=status.HTTP_200_OK,
|
|
143
|
+
)
|