master
Mustafa Yontar 3 years ago
commit 8432ffe449
  1. 25
      .gitignore
  2. 147
      adunatio.md
  3. 0
      docker-compose.yaml
  4. 69
      internal_lib/EncryptedField.py
  5. 0
      internal_lib/__init__.py
  6. 16
      main.py
  7. 10
      models/Account.py
  8. 8
      models/EmbededDocuments.py
  9. 15
      models/File.py
  10. 15
      models/Group.py
  11. 28
      models/Payment.py
  12. 9
      models/Union.py
  13. 96
      models/User.py
  14. 0
      models/__init__.py
  15. 4
      requirements.txt

25
.gitignore vendored

@ -0,0 +1,25 @@
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
.venv/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
.idea/
*.pem
*test.py
trash

@ -0,0 +1,147 @@
# Dernek yazılımı
Türkiye'de faal derneklerin, mevcut mevzuata dahil olarak derneğin yasal süreçlerini, üye ilişkilerini ve muhasebelerini takip edebilmeleri için bir yazılım geliştirilmesi gerekliliği ortaya atılmıştır.
## Temel gereksinimler
Yazılımın temel gereksinimlerini n ayrı başlıkta inceleyebiliriz:
* Defterlerin tutulması
* Gelir/gider takibi
* Üye takibi
* Evrak/dosya takibi
* Aidat takibi
* Bilgi e-postası / formu takibi
* Genel kurul süreç takibi
* E-posta ve SMS ile toplu duyurular
* Aidat ödeme (iyzico)
### Defterlerin tutulması
Dernekler 4 adet defter tutmak zorundadır:
* Karar defteri
* İşletme defteri
* Üye kayıt defteri
* Evrak kayıt defteri
5253 sayılı Dernekler Kanunu uyarınca bu defterler elektronik ortamda tutulabilir, ancak önceden Sivil Toplumla İlişkiler Müdürlüğü tarafından mühürlenmiş numaralı kağıtlara yazdırılarak saklanmalıdır. Bu defterlerin şekli standarda bağlanmış olup siviltoplum.gov.tr adresinde mevcuttur.
#### Karar defteri
Karar defteri, dernek yönetim kurulunun aldığı kararların yazıldığı temel defterdir. Bu defterde aşağıdaki alanlar mevcuttur:
* Karar numarası: Her karara sırayla numara veriliyor (unsigned int), bu numaralar 1'den başlıyor. Tarih sırası ile numara sırası sabit gitmek zorunda, yani 5 numaralı kararın tarihi 4 numaralı karardan eski olamaz.
* Tarih: Karar tarihi, GG/AA/YYYY
* Konu: String field, kararın ne hakkında olduğu yazılıyor.
* Toplantıya katılan üyeler: Kararın alındığı toplantıya katılan kişilerin adı soyadı, bunları yönetim kurulu listesinden çekebiliriz. Başkan ve üyeler diye iki ayrı field var.
* Kararın metni: Karar metni, standart.
* İmzalar: Katılan her üye için metnin altında imza alanı oluyor, kişiler isimlerinin üzerine imza atıyor.
#### Üye kayıt defteri
Üye kayıt defteri, derneğe üye olan her üyenin bilgilerinin işlendiği bir defterdir. Bu defteri yazılım içinde üyeler diye bir başlık altında defter formatından bağımsız olarak tutmak daha kullanışlı olabilir. Bu defterde normalde aşağıdaki alanlar mevcut:
* Fotoğraf: üyenin fotoğrafı, 25x35 mm
* Adı soyadı
* TCKN
* Tabiiyeti
* Ana adı
* Baba adı
* Cinsiyeti
* Mesleği
* E-posta adresi
* İkametgah adresi
* Üyeliğe kabul tarihi
* Üyelikten çıkma tarihi
* Açıklamalar
*
Bunlara ek olarak, üye aidatı tahsilatı diye bir alanı daha var, bu alanda da her bir giriş için yılı, alındı belgesinin tarihi+sıra no, tutarı (lira+kr) alanları mevcut.
#### İşletme defteri
Derneğin muhasebe kayıtlarının tutulduğu defterdir. Sol sayfada giderler, sağ sayfada gelirler yazılıdır. Her bir sayfa önceki sayfadan nakil toplam ile başlar, sonra her satır için:
* Sıra no
* Alındı belgesinin tarihi+no
* Açıklama
* Tutar (Lira+Kr)
En son satırda da yazıyla ve sayıyla toplam tutar yazılır.
#### Evrak kayıt defteri
Evrak kayıt defteri, derneğe gelen ve giden her nevi evrakın yazıldığı defterdir. Üye başvuruları, verilen cevaplar, gelen bildirimler vs. hepsi yazılır, denetimlerde genelde çok bakılmaz. Sol sayfada gelen evrak, sağ sayfada giden evrak yazılır. Her bir satırda:
* Kayıt sıra no
* Geldiği kişi veya kurum
* Tarihi
* Sayısı
* Eki
* Konusu
* Muhafaza edildiği dosya no
Belgeler diye bir sayfa yapıp, her bir girdi için PDF eklenebilse çok güzel olur.
### Gelir-gider takibi
Derneğin gelirleri ve giderlerinin kategori bazlı olarak takibini ve borçlar/alacakların kurulması önemli bir konu, bunun için yazılımda en olmazsa olmaz kısımlardan bir tanesi.
Temel olarak gider ve gelir kategorileri atanacak ve bu kategorilere harcama/gelir yazılacak. Her bir harcama/gelir için:
* Tarih
* Hesap
* Alıcı/bağışçı ismi
* TCKN/VKN
* Açıklama
* Referans no
* Makbuz/fatura (PDF)
* Düzenli mi? (Haftalık-Aylık-Yıllık)
Düzenli olarak işaretlenen giderler, her ayın o günü yaklaşırken e-posta uyarısı vermeli.
### Üye takibi
Dernek üyelerinin profilleri buraya girilecek, üye kayıt defteri buna göre oluşturulacak. Her üye için:
* Üye no (1'den başlayarak sırayla)
* Kullanıcı adı/parola (kendileri servise girip aidat vs ödeme yapabilsinler diye)
* Ad soyad
* TCKN
* Ana adı
* Baba adı
* Doğum tarihi
* Cinsiyet
* Meslek
* E-posta
* Telefon
* Adres
* Üyeliğe giriş tarihi
* Üyelikten çıkış tarihi
* Üyelik tipi (asıl-destekçi-onursal)
* Aidat tipi (Tam, indirimli)
* Yorumlar/Açıklamalar
* GnuPG Fingerprint
### Evrak/dosya takibi
Belgeler diye bir alanda, PDF vb. belgelerin yüklenip kategorize edilebileceği bir bölüm iyi olacaktır. Evrak kayıt defteri de burada gelen evrak/giden evrak kategorilerinden oluşturulabilir.
### Aidat takibi
En önemli işlerden birisi bu, her üyenin aidat tipine göre ve yıllık aidat miktarına göre üyelere borç yazılması ve hangi üyenin ne kadar borcunun olduğunun takip edilmesi lazım. Ayrıca üyelerin yaptıkları genel bağışların da tutulması lazım. Örneğin aylık aidat 40 lira ise, aidatlarım diye bir sekmede üyelerin ay ay aidatlarını ödeyip ödemediklerinin görülebilmesi, eğer toplu ödedilerse (örneğin 6 aylık peşin 240 lira) altı ayın üstünün çizilmesi lazım. Üyelere borç hatırlatmasının yapılması, aidat tahsilatının hangi yolla yapıldığının girilebilmesi lazım.
### Bilgi e-postası / formu takibi
Orta öncelikli bir konu olarak, bilgi formuna veya e-postasına düşen e-postaların görülebileceği ve mümkünse cevaplanabileceği bir alan faydalı olabilir.
### E-posta ve SMS ile toplu duyurular
Üyelerin tamamına veya bir kısmına e-posta ve SMS ile duyuru atılabilmesi ihtiyacı var, e-posta için standart SMTP iş görür, SMS için Verimor API entegrasyonu lazım.
<https://github.com/verimor/SMS-API>
### Aidat ödeme (iyzico)
Üyelerin kendi aidat borçlarını görüp, bunları iyzico ile ödeyebilmeleri ve otomatik ödemeye bağlayabilmeleri lazım. Kart değişikliği veya otomatik ödeme iptali, isteğe bağlı ödeme de lazım.

@ -0,0 +1,69 @@
import re
from mongoengine.base import BaseField
from mongoengine.queryset import STRING_OPERATORS
class EncryptedStringField(BaseField):
"""A unicode string field."""
def __init__(self, regex=None, max_length=None, min_length=None, **kwargs):
"""
:param regex: (optional) A string pattern that will be applied during validation
:param max_length: (optional) A max length that will be applied during validation
:param min_length: (optional) A min length that will be applied during validation
:param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.BaseField`
"""
self.regex = re.compile(regex) if regex else None
self.max_length = max_length
self.min_length = min_length
super().__init__(**kwargs)
def to_python(self, value):
if isinstance(value, str):
return value
try:
value = value.decode("utf-8")
except Exception:
pass
return value
def validate(self, value):
if not isinstance(value, str):
self.error("StringField only accepts string values")
if self.max_length is not None and len(value) > self.max_length:
self.error("String value is too long")
if self.min_length is not None and len(value) < self.min_length:
self.error("String value is too short")
if self.regex is not None and self.regex.match(value) is None:
self.error("String value did not match validation regex")
def lookup_member(self, member_name):
return None
def prepare_query_value(self, op, value):
if not isinstance(op, str):
return value
if op in STRING_OPERATORS:
case_insensitive = op.startswith("i")
op = op.lstrip("i")
flags = re.IGNORECASE if case_insensitive else 0
regex = r"%s"
if op == "startswith":
regex = r"^%s"
elif op == "endswith":
regex = r"%s$"
elif op == "exact":
regex = r"^%s$"
# escape unsafe characters which could lead to a re.error
value = re.escape(value)
value = re.compile(regex % value, flags)
return super().prepare_query_value(op, value)

@ -0,0 +1,16 @@
# This is a sample Python script.
# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
def print_hi(name):
# Use a breakpoint in the code line below to debug your script.
print(f'Hi, {name}') # Press Ctrl+8 to toggle the breakpoint.
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
print_hi('PyCharm')
# See PyCharm help at https://www.jetbrains.com/help/pycharm/

@ -0,0 +1,10 @@
from mongoengine import *
from models.Union import Union
class Account(Document):
union = ReferenceField(Union)
bank = StringField()
number = StringField()
quick_number = StringField()

@ -0,0 +1,8 @@
from mongoengine import *
class Descriptions(EmbeddedDocument):
from models.User import User
text = StringField()
user = ReferenceField(User)
date = DateTimeField()

@ -0,0 +1,15 @@
from mongoengine import *
from models.Group import Group
class Directory(Document):
path = StringField()
can_see_user_group = ReferenceField(Group)
is_system = BooleanField(default=False)
class File(Document):
path = ReferenceField(Directory)
file = FileField()
description = StringField()

@ -0,0 +1,15 @@
from mongoengine import *
from models.Union import Union
class Group(Document):
union = ReferenceField(Union)
name = StringField()
rights = StringField()
class PaymentGroup(Document):
union = ReferenceField(Union)
name = StringField()
discount_percent = IntField()

@ -0,0 +1,28 @@
from mongoengine import *
from models.Account import Account
from models.File import File
from models.Union import Union
from models.User import User
class Payments(Document):
"""
all payments income and outcome together!
"""
union = ReferenceField(Union)
user = ReferenceField(User)
income = BooleanField(default=False)
date = DateTimeField()
regular = BooleanField(default=False)
regular_type = StringField(choices=('Weekly','Monthly','Yearly'))
price = DecimalField()
description = StringField()
reference_no = StringField()
file = ReferenceField(File)
account = ReferenceField(Account)
due_date = DateTimeField()
is_paid = BooleanField(default=False)
is_donate = BooleanField(default=False)

@ -0,0 +1,9 @@
from mongoengine import *
class Union(Document):
name = StringField()
logo = ImageField(thumbnail_size=(120,120))
description = StringField()
legal_registration_number = StringField()
headquarter = StringField()

@ -0,0 +1,96 @@
from mongoengine import *
from internal_lib.EncryptedField import EncryptedStringField
from models.EmbededDocuments import Descriptions
from models.Group import Group
from models.Union import Union
class User(Document):
union = ReferenceField(Union)
member_no = LongField()
username = StringField()
photo = ImageField(thumbnail_size=(85,120))
password = StringField()
name = StringField()
middle_name = StringField()
last_name = StringField()
gov_id = EncryptedStringField()
mother_name = EncryptedStringField()
father_name = EncryptedStringField()
email = EncryptedStringField()
place_of_birth = EncryptedStringField()
date_of_birth = EncryptedStringField()
telephone = EncryptedStringField()
job = StringField()
address = EncryptedStringField()
accept_date = DateTimeField()
dismissal_date = DateTimeField()
descriptions = ListField(EmbeddedDocumentField(Descriptions))
gender = StringField(choices=(
'Man',
'Women',
'Agender',
'Androgyne',
'Androgynous',
'Bigender',
'Cis',
'Cisgender',
'Cis Female',
'Cis Male',
'Cis Man',
'Cis Woman',
'Cisgender Female',
'Cisgender Male',
'Cisgender Man',
'Cisgender Woman',
'Female to Male',
'FTM',
'Gender Fluid',
'Gender Nonconforming',
'Gender Questioning',
'Gender Variant',
'Genderqueer',
'Intersex',
'Male to Female',
'MTF',
'Neither',
'Neutrois',
'Non-binary',
'Other',
'Pangender',
'Trans',
'Trans*',
'Trans Female',
'Trans* Female',
'Trans Male',
'Trans* Male',
'Trans Man',
'Trans* Man',
'Trans Person',
'Trans* Person',
'Trans Woman',
'Trans* Woman',
'Transfeminine',
'Transgender',
'Transgender Female',
'Transgender Male',
'Transgender Man',
'Transgender Person',
'Transgender Woman',
'Transmasculine',
'Transsexual',
'Transsexual Female',
'Transsexual Male',
'Transsexual Man',
'Transsexual Person',
'Transsexual Woman',
'Two-Spirit'
))
gnupg_fingerprint = StringField()
user_group = ReferenceField(Group)
payment_group = ReferenceField(Group)

@ -0,0 +1,4 @@
mongoengine
flask-mongoengine
flask
pycryptodome
Loading…
Cancel
Save