|
1 | | -# Getting started (Local) |
| 1 | +<p align="center"> |
| 2 | + <p align="center"> |
| 3 | + <a href="https://finmars.io/?utm_source=github&utm_medium=logo" target="_blank"> |
| 4 | + <img src="https://github.com/finmars-platform/finmars-core/blob/main/finmars-misc/logo_white_bg.png" alt="Finmars" height="84" /> |
| 5 | + </a> |
| 6 | + </p> |
| 7 | +</p> |
2 | 8 |
|
3 | | -**Works for python 3.11** |
| 9 | +# Open Source Finance Management Platform |
4 | 10 |
|
5 | | -* Install NPM |
6 | | -* Install Python 3.9 |
7 | | -* Install Docker and Docker Compose |
| 11 | +Finmars is a **free, open-source** platform to help you manage all your money and investments in one place. You can pull in data from many accounts and see it together. |
| 12 | +\ |
| 13 | +It gives you easy tools to create reports, dashboards, and PDFs without writing code. |
| 14 | +You can add extra features from our open marketplace — just pick what you need and plug it in. |
| 15 | +Finmars runs in your web browser, so you and your team can use it from anywhere. |
8 | 16 |
|
9 | | -* Install ubuntu applications |
| 17 | +<p align="center"> |
| 18 | + <img src="https://github.com/finmars-platform/finmars-core/blob/main/finmars-misc/dashboard.png" width="270" /> |
| 19 | + <img src="https://github.com/finmars-platform/finmars-core/blob/main/finmars-misc/report.png" width="270" /> |
| 20 | + <img src="https://github.com/finmars-platform/finmars-core/blob/main/finmars-misc/book.png" width="270" /> |
| 21 | + <img src="https://github.com/finmars-platform/finmars-core/blob/main/finmars-misc/matrix.png" width="270" /> |
| 22 | +</p> |
10 | 23 |
|
11 | | -`apt-get update && apt-get install -y apt-utils && apt-get upgrade -y && apt-get install -y wget htop curl build-essential openssl libssl-dev python3.9-dev python3-pip python3.9-venv python3-setuptools python3-wheel libpq-dev libgdal-dev libgeos-dev libproj-dev libtiff5-dev libjpeg-turbo8-dev libzip-dev zlib1g-dev libffi-dev git libgeoip-dev geoip-bin geoip-database supervisor` |
| 24 | +## Community Edition |
12 | 25 |
|
13 | | -* Create Virtual Environment (VENV) |
| 26 | +To install and to start using Finmars please refer [Getting Started Community Edition](https://docs.finmars.com/shelves/community-edition). |
14 | 27 |
|
15 | | -* Activate VENV |
| 28 | +Also see [finmars-community-edition](https://github.com/finmars-platform/finmars-community-edition) repository. |
16 | 29 |
|
17 | | -* Install Dependencies |
| 30 | +#### Self-Hosting with Docker Compose |
| 31 | +This is the simplest way to get a local Finmars instance running. |
18 | 32 |
|
19 | | -* Create file for logs |
| 33 | +On Linux or Mac Enviroment: |
| 34 | +```bash |
| 35 | +# Clone the Finmars Community Edition repository |
| 36 | +git clone https://github.com/finmars-platform/finmars-community-edition.git |
20 | 37 |
|
21 | | -`mkdir -p /var/log/finmars` |
22 | | -`chmod 777 /var/log/finmars/` |
23 | | -`touch /var/log/finmars/django.log` |
24 | | -`chmod 777 /var/log/finmars/django.log` |
| 38 | +# Navigate to the repository |
| 39 | +cd finmars-community-edition |
25 | 40 |
|
26 | | -* Install Celery |
| 41 | +# Configure env file |
| 42 | +vim .env |
27 | 43 |
|
28 | | -`pip install celery` |
| 44 | +# Run Migrations |
| 45 | +make migrate |
29 | 46 |
|
30 | | -* Start Postgres Database and Redis in docker |
31 | | - |
32 | | -`docker-compose -f docker-compose-dev.yml up` |
33 | | - |
34 | | -* Run Migrations |
35 | | - |
36 | | -`./local-development/run_migrate.sh` |
37 | | - |
38 | | -* Start Celery Server |
39 | | - |
40 | | -`./local-development/run_celery.sh` |
41 | | - |
42 | | -* Start Django Server |
43 | | - |
44 | | -`./local-development/run_server.sh` |
45 | | - |
46 | | -Success! |
47 | | - |
48 | | - |
49 | | -How to run django app |
50 | | - |
51 | | -1) Activate venv |
52 | | - |
53 | | - `source venv/bin/activate` |
54 | | - |
55 | | -2) Install PyInstaller==3.4 |
56 | | - |
57 | | - `pip install pyinstaller==3.4.` |
58 | | - |
59 | | -3) Execute following command to build |
60 | | - |
61 | | - `REDIS_HOST=localhost DB_NAME=finmars_dev DB_USER=postgres DB_PASSWORD=postgres DB_HOST=localhost DB_PORT=5434 python3 -m PyInstaller backend.spec -y --debug --log-level TRACE` |
62 | | - |
63 | | -4) Execute following script to runserver |
64 | | - |
65 | | - `./local-development/run_server.sh` |
66 | | - |
67 | | -Profile uWSGI server |
68 | | -1) Activate venv |
69 | | -`source /var/app-venv/bin/activate` |
70 | | -2) Run Profiler |
71 | | -`uwsgitop /tmp/stats.socket` |
72 | | - |
73 | | - |
74 | | -## Backend Settings |
75 | | - |
76 | | -We can setup backend in several ways passing ENV VARIABLE `BACKEND_ROLES`: |
77 | | -Possible values of `BACKEND_ROLES`: |
78 | | - |
79 | | -* `ALL` - Default role, if nothing is passed. Backend instance do all services. |
80 | | -* `SIMPLE` - Simple backend instance - Auth / CRUD for all entities / Configuration Export/Import |
81 | | -* `REPORTER` - All Reports |
82 | | -* `FILE_IMPORTER` - Simple Entity Import / Complex Transaction File imports |
83 | | -* `DATA_PROVIDER` - Providers (Bloomberg) interaction |
84 | | - |
85 | | -You can pass several roles to Backend instance. |
86 | | -Example : `REPORTER, FILE_IMPORTER, DATA_PROVIDER` |
87 | | - |
88 | | -P.S. You also need to specify your nginx config to route correctly. |
89 | | - |
90 | | - |
91 | | -`docker-compose.yml` - Сейчас нигде не используется |
92 | | - |
93 | | -`docker-compose-dev.yml` - Используется для локальной разработки |
94 | | - |
95 | | -`Dokerfile` - тот файл который использует Jenkins для сборки итогового билда |
96 | | - |
97 | | -`docker` - набор скриптов которые использует Dokerfile для итогового image |
98 | | - |
99 | | - |
100 | | - |
101 | | - |
102 | | -Что можно сделать |
103 | | -1) Сделать сборки локальной версии и той что на серверах максимально похожими (Сейчас очень сильно олтичаются Celery) |
104 | | - |
105 | | - |
106 | | - |
107 | | - |
108 | | - |
109 | | - |
110 | | - |
111 | | - |
112 | | - |
113 | | - |
114 | | - |
115 | | - |
116 | | - |
117 | | - |
118 | | - |
119 | | - |
120 | | - |
121 | | - |
122 | | -Usefull code: Replace to_representation in rest_framework/serializers.py with code below, and you will get time explanation of each field serializaton |
123 | | - |
124 | | -``` |
125 | | -def to_representation(self, instance): |
126 | | - """ |
127 | | - Object instance -> Dict of primitive datatypes. |
128 | | - """ |
129 | | - ret = OrderedDict() |
130 | | - fields = self._readable_fields |
131 | | -
|
132 | | - st = time.perf_counter() |
133 | | -
|
134 | | - for field in fields: |
135 | | - try: |
136 | | - attribute = field.get_attribute(instance) |
137 | | - except SkipField: |
138 | | - continue |
139 | | -
|
140 | | - field_st = time.perf_counter() |
141 | | -
|
142 | | - # We skip `to_representation` for `None` values so that fields do |
143 | | - # not have to explicitly deal with that case. |
144 | | - # |
145 | | - # For related fields with `use_pk_only_optimization` we need to |
146 | | - # resolve the pk value. |
147 | | - check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute |
148 | | - if check_for_none is None: |
149 | | - ret[field.field_name] = None |
150 | | - else: |
151 | | - ret[field.field_name] = field.to_representation(attribute) |
152 | | -
|
153 | | - if 'item_' in field.field_name: |
154 | | - if hasattr(instance, 'is_report'): |
155 | | - print('Field %s ' % field.field_name) |
156 | | - print('Field to representation done %s' % (time.perf_counter() - field_st)) |
157 | | -
|
158 | | - if hasattr(instance, 'is_report'): |
159 | | - print('Report to representation done %s' % (time.perf_counter() - st)) |
160 | | -
|
161 | | - return ret |
162 | | -
|
163 | | -``` |
164 | | - |
165 | | -### IDEA settings |
166 | | - |
167 | | -#### SQL proper formatting in python string |
168 | | - |
169 | | -Settings -> Tools -> Database -> User Parameters -> Enable in string literals with SQL injection |
170 | | -`\{(\w+)\}` for Python |
171 | | - |
172 | | - |
173 | | -- Token Refrsh |
174 | | - |
175 | | - |
176 | | - |
177 | | -CELERY |
178 | | - |
179 | | - |
180 | | -Celery worker |
181 | | - Сам не процессить, генерит процессы, поэтому вроде как финмарсу нету смысла иметь больше 1 воркера на проект |
182 | | - |
183 | | - |
184 | | -Apple Silicon |
185 | | - |
186 | | -export LIBRARY_PATH=$LIBRARY_PATH:/opt/homebrew/opt/openssl/lib |
187 | | -pip install -r requirements.txt |
188 | | - |
189 | | -Reset sequence |
190 | | - |
191 | | -python manage.py sqlsequencereset app_label | python manage.py dbshell |
192 | | -e.g. |
193 | | -python manage.py sqlsequencereset portfolios | python manage.py dbshell |
194 | | - |
195 | | - |
196 | | - |
197 | | -# Install all required libs |
198 | | - |
199 | | -==== TODO ==== |
200 | | -Move generated documentation to another project |
201 | | - |
202 | | -How to generate documentation |
203 | | -``` |
204 | | -if [ "${ENABLE_DEV_DOCUMENTATION}" == "True" ]; then |
205 | | -echo "Generating dev documentation" |
206 | | -cd /var/app/docs/source && sphinx-apidoc -o ./files ../../ ../../*migrations* ../../*tests* ../../*admin* ../../*apps* --separate --module-first |
207 | | -echo "Documentation generated. Going to create html" |
208 | | -cd /var/app/docs && make html |
209 | | -echo "HTML Documentation generated" |
210 | | -else |
211 | | -echo "Dev documentation skip" |
212 | | -fi |
213 | | -``` |
214 | | - |
215 | | -# Postgresql Magic |
216 | | - |
217 | | -## Reset sequence |
218 | | - |
219 | | -python manage.py sqlsequencereset transactions |
220 | | - |
221 | | -## Find duplicates |
222 | | - |
223 | | -from django.db.models import Count |
224 | | -from poms.transactions.models import ComplexTransaction |
225 | | -ComplexTransaction.objects.values("id").annotate(did=Count("id")).filter(did__gt=1) |
226 | | - |
227 | | - |
228 | | -from django.db.models import Count |
229 | | -from poms.transactions.models import Transaction |
230 | | -Transaction.objects.values("id").annotate(did=Count("id")).filter(did__gt=1) |
231 | | - |
232 | | -## Show Duplicates |
233 | | - |
234 | | -(SELECT ctid |
235 | | -FROM |
236 | | -(SELECT id, ctid, |
237 | | -ROW_NUMBER() OVER( PARTITION BY id |
238 | | -ORDER BY id ) AS row_num |
239 | | -FROM transactions_complextransaction ) t |
240 | | -WHERE t.row_num > 1 ); |
241 | | - |
242 | | -## Delete duplicated ids |
243 | | - |
244 | | -DELETE FROM transactions_complextransaction |
245 | | -WHERE ctid IN |
246 | | -(SELECT ctid |
247 | | -FROM |
248 | | -(SELECT id, ctid, |
249 | | -ROW_NUMBER() OVER( PARTITION BY id |
250 | | -ORDER BY id ) AS row_num |
251 | | -FROM transactions_complextransaction ) t |
252 | | -WHERE t.row_num > 1 ); |
253 | | - |
254 | | -DELETE FROM transactions_transaction |
255 | | -WHERE ctid IN |
256 | | -(SELECT ctid |
257 | | -FROM |
258 | | -(SELECT id, ctid, |
259 | | -ROW_NUMBER() OVER( PARTITION BY id |
260 | | -ORDER BY id ) AS row_num |
261 | | -FROM transactions_transaction ) t |
262 | | -WHERE t.row_num > 1 ); |
263 | | - |
264 | | - |
265 | | - |
266 | | -# Access policy |
267 | | - |
268 | | -frn:[service]:[content_type]:[user_code] |
269 | | -frn:finmars:portfolios.portfolio:portfolio_1 |
270 | | - |
271 | | -# Celery articles |
272 | | -https://engineering.backmarket.com/a-story-of-kubernetes-celery-resource-and-a-rabbit-ec2ef9e37e9f |
273 | | -https://ayushshanker.com/posts/celery-in-production-bugfixes/ |
274 | | - |
275 | | - |
276 | | - |
277 | | -### Guideline |
278 | | - |
279 | | -Не используются тернарные операторы (e.g. foo ? bar : buz) |
280 | | -Не используется синтаксический сахар вида `i++ (а не i = i + 1)` |
281 | | -использование camelCase а не camel_case в названии переменных и методов (классы обязательно называть CamelCaseModel и тд) |
282 | | -мне не нравится сложный код, я бы сократил возможно использование лямда функций |
283 | | -мне нравится декларация функций внутри функции, такое просто надо сносить в utils.py какой нибудь |
284 | | -Если пишет про джангу то, стараться к моделям сразу делать и админку, также прописывать все сериализаторы, чтобы в веб интерфейсе можно было запустить точку апи |
285 | | -При объявлении полей модели писать help_text |
286 | | -На текущий момент все @finmars_task как входной параметр должны принимать task_id (от CeleryTask) |
287 | | -В таска nice to have прописывать progress этого таска |
288 | | - |
289 | | - |
290 | | - |
291 | | -Еще мне очень нравится пример: |
292 | | -``` |
293 | | -router.register( |
294 | | -r"csv", |
295 | | -csv_import.CsvDataImportViewSet, |
296 | | -"import_csv", |
297 | | -) |
298 | | -``` |
| 47 | +# Run Finmars |
| 48 | +make up |
299 | 49 |
|
300 | 50 | ``` |
301 | | -router.register(r"csv", csv_import.CsvDataImportViewSet, "import_csv") |
302 | | -``` |
303 | | -то есть я что имею ввиду, если идет много однотипных деклараций, то лучше их без word-wrap писать |
304 | | -Если функция принимает на вход хотябы 5 параметров, тогда я могу понять перенос по параметрам |
305 | | -но если мы переносим по параметрам, я бы делал вид |
306 | | - |
307 | | -``` |
308 | | -router.register( |
309 | | -prefix=r"csv", |
310 | | -viewset=csv_import.CsvDataImportViewSet, |
311 | | -basename="import_csv", |
312 | | -) |
313 | | -``` |
314 | | - |
315 | | - |
316 | | -# Versioning |
317 | | - |
318 | | -* `main` - Start when PR merge in `main` branch. Increment patch version and publish release candidate image. |
319 | | -* `release` - Start manually from `main` branch. Increment minor version and publish stable image |
320 | | -* `patch_release` - Start manually from `main` branch. Publish current version stable image |
321 | 51 |
|
| 52 | +## License |
| 53 | +Please refer to the [LICENSE](https://github.com/finmars-platform/finmars-core/blob/main/LICENSE.md) file for a copy of the license. |
322 | 54 |
|
323 | | -# First start |
324 | 55 |
|
325 | | -1) make generate-env |
326 | | -2) make import-sql (fror demo or restore db from dump) |
327 | | -3) make migrate |
328 | | -4) make up |
| 56 | +## Support |
| 57 | +Please use the GitHub issues for support, feature requests and bug reports, or contact us by sending an email to support@finmars.com. |
0 commit comments