Skip to content

Commit

Permalink
Merge pull request #155 from pythonkr/feature/sponsor
Browse files Browse the repository at this point in the history
후원사 구좌 및 혜택 관리 API 추가
  • Loading branch information
jungmir authored Aug 28, 2024
2 parents f0ea6f5 + 45347c8 commit 759a5ab
Show file tree
Hide file tree
Showing 10 changed files with 395 additions and 27 deletions.
11 changes: 8 additions & 3 deletions pyconkr/settings-localtest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

from pyconkr.settings import *
from pyconkr.settings import * # noqa

DEBUG = True

Expand All @@ -10,10 +10,15 @@


# RDS
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "local.sqlite3",
}
}

# django-storages: TODO fix to in memory?
del MEDIA_ROOT
del MEDIA_ROOT # noqa
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
STATICFILES_STORAGE = "storages.backends.s3boto3.S3StaticStorage"
AWS_S3_ACCESS_KEY_ID = os.getenv("AWS_S3_ACCESS_KEY_ID")
Expand Down
14 changes: 9 additions & 5 deletions pyconkr/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""

import os
import pathlib

Expand Down Expand Up @@ -81,9 +82,10 @@
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates" ,
BASE_DIR / "accounts/templates",
],
"DIRS": [
BASE_DIR / "templates",
BASE_DIR / "accounts/templates",
],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
Expand Down Expand Up @@ -139,7 +141,9 @@
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
Expand Down Expand Up @@ -219,7 +223,7 @@
"https://2023.pycon.kr",
"https://pycon-dev2023.pycon.kr",
"https://pycon-prod2023.pycon.kr",
"https://ticket-2023.pycon.kr", # PG 심사 대비 임시 도메인
"https://ticket-2023.pycon.kr", # PG 심사 대비 임시 도메인
"https://127.0.0.1:3000",
"https://localhost:3000",
"http://2023.pycon.kr",
Expand Down
50 changes: 50 additions & 0 deletions sponsor/migrations/0006_sponsorbenefit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Generated by Django 4.1.5 on 2024-07-28 12:17

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("sponsor", "0005_patron"),
]

operations = [
migrations.CreateModel(
name="SponsorBenefit",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(help_text="혜택 이름", max_length=255)),
("desc", models.TextField(blank=True, help_text="기타", null=True)),
("offer", models.PositiveIntegerField(help_text="제공 하는 혜택 개수")),
("unit", models.CharField(help_text="혜택 단위", max_length=10)),
(
"is_countable",
models.BooleanField(
default=True, help_text="제공 하는 혜택이 셀 수 있는지 여부"
),
),
(
"sponsor_level",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="benefits",
to="sponsor.sponsorlevel",
),
),
],
options={
"verbose_name": "후원사 등급 별 혜택",
"verbose_name_plural": "후원사 등급 별 혜택 목록",
},
),
]
59 changes: 59 additions & 0 deletions sponsor/migrations/0007_remove_sponsorbenefit_offer_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Generated by Django 4.1.5 on 2024-08-06 12:41

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("sponsor", "0006_sponsorbenefit"),
]

operations = [
migrations.RemoveField(
model_name="sponsorbenefit",
name="offer",
),
migrations.RemoveField(
model_name="sponsorbenefit",
name="sponsor_level",
),
migrations.CreateModel(
name="BenefitByLevel",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("offer", models.PositiveIntegerField(help_text="제공 하는 혜택 개수")),
(
"benefit",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="benefit_by_level",
to="sponsor.sponsorbenefit",
),
),
(
"level",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="benefit_by_level",
to="sponsor.sponsorlevel",
),
),
],
),
migrations.AddConstraint(
model_name="benefitbylevel",
constraint=models.UniqueConstraint(
fields=("benefit_id", "level_id"), name="IX_BENEFIT_BY_LEVEL_1"
),
),
]
13 changes: 13 additions & 0 deletions sponsor/migrations/0008_merge_20240806_2206.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Generated by Django 4.1.5 on 2024-08-06 13:06

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("sponsor", "0006_sponsorlevel_year"),
("sponsor", "0007_remove_sponsorbenefit_offer_and_more"),
]

operations = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 4.1.5 on 2024-08-06 14:27

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("sponsor", "0008_merge_20240806_2206"),
]

operations = [
migrations.AddField(
model_name="sponsorbenefit",
name="year",
field=models.IntegerField(default=2023),
),
migrations.AddField(
model_name="sponsorlevel",
name="benefits",
field=models.ManyToManyField(
related_name="level",
through="sponsor.BenefitByLevel",
to="sponsor.sponsorbenefit",
),
),
]
69 changes: 59 additions & 10 deletions sponsor/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,32 @@ def get_queryset(self):
return super(SponsorLevelManager, self).get_queryset().all().order_by("order")


class SponsorBenefit(models.Model):
class Meta:
verbose_name = "후원사 등급 별 혜택"
verbose_name_plural = "후원사 등급 별 혜택 목록"

name = models.CharField(max_length=255, help_text="혜택 이름")
desc = models.TextField(null=True, blank=True, help_text="기타")
unit = models.CharField(max_length=10, help_text="혜택 단위")
year = models.IntegerField(default=2023)
is_countable = models.BooleanField(
default=True, help_text="제공 하는 혜택이 셀 수 있는지 여부"
)


class SponsorLevel(models.Model):
class Meta:
verbose_name = "후원사 등급"
verbose_name_plural = "후원사 등급"

name = models.CharField(max_length=255, blank=True, default="", help_text="후원 등급명")
name = models.CharField(
max_length=255, blank=True, default="", help_text="후원 등급명"
)
desc = models.TextField(
null=True, blank=True, help_text="후원 혜택을 입력하면 될 거 같아요 :) 후원사가 등급을 정할 때 볼 문구입니다."
null=True,
blank=True,
help_text="후원 혜택을 입력하면 될 거 같아요 :) 후원사가 등급을 정할 때 볼 문구입니다.",
)
visible = models.BooleanField(default=True)
price = models.IntegerField(default=0)
Expand All @@ -27,6 +45,10 @@ class Meta:
updated_at = models.DateTimeField(auto_now=True)
year = models.IntegerField(default=2023)

benefits = models.ManyToManyField(
SponsorBenefit, through="BenefitByLevel", related_name="level"
)

objects = SponsorLevelManager()

@property
Expand All @@ -51,6 +73,23 @@ def __str__(self):
return self.name


class BenefitByLevel(models.Model):
class Meta:
constraints = [
models.UniqueConstraint(
fields=["benefit_id", "level_id"], name="IX_BENEFIT_BY_LEVEL_1"
)
]

benefit = models.ForeignKey(
SponsorBenefit, on_delete=models.CASCADE, related_name="benefit_by_level"
)
level = models.ForeignKey(
SponsorLevel, on_delete=models.CASCADE, related_name="benefit_by_level"
)
offer = models.PositiveIntegerField(help_text="제공 하는 혜택 개수")


def registration_file_upload_to(instance, filename):
return f"sponsor/business_registration/{instance.id}/{filename}"

Expand Down Expand Up @@ -78,7 +117,8 @@ class Meta:
related_name="sponsor_creator",
)
name = models.CharField(
max_length=255, help_text="후원사의 이름입니다. 서비스나 회사 이름이 될 수 있습니다."
max_length=255,
help_text="후원사의 이름입니다. 서비스나 회사 이름이 될 수 있습니다.",
)
level = models.ForeignKey(
SponsorLevel,
Expand All @@ -88,13 +128,18 @@ class Meta:
help_text="후원을 원하시는 등급을 선택해주십시오. 모두 판매된 등급은 선택할 수 없습니다.",
)
desc = models.TextField(
null=True, blank=True, help_text="후원사 설명입니다. 이 설명은 국문 홈페이지에 게시됩니다."
null=True,
blank=True,
help_text="후원사 설명입니다. 이 설명은 국문 홈페이지에 게시됩니다.",
)
eng_desc = models.TextField(
null=True, blank=True, help_text="후원사 영문 설명입니다. 이 설명은 영문 홈페이지에 게시됩니다."
null=True,
blank=True,
help_text="후원사 영문 설명입니다. 이 설명은 영문 홈페이지에 게시됩니다.",
)
manager_name = models.CharField(
max_length=100, help_text="준비위원회와 후원과 관련된 논의를 진행할 담당자의 이름을 입력해주십시오."
max_length=100,
help_text="준비위원회와 후원과 관련된 논의를 진행할 담당자의 이름을 입력해주십시오.",
)
manager_email = models.CharField(
max_length=100,
Expand Down Expand Up @@ -149,10 +194,13 @@ class Meta:
help_text="사용자가 제출했는지 여부를 저장합니다. 요청이 제출되면 준비위원회에서 검토하고 받아들일지를 결정합니다.",
)
accepted = models.BooleanField(
default=False, help_text="후원사 신청이 접수되었고, 입금 대기 상태인 경우 True로 설정됩니다."
default=False,
help_text="후원사 신청이 접수되었고, 입금 대기 상태인 경우 True로 설정됩니다.",
)
paid_at = models.DateTimeField(
null=True, blank=True, help_text="후원금이 입금된 일시입니다. 아직 입금되지 않았을 경우 None이 들어갑니다."
null=True,
blank=True,
help_text="후원금이 입금된 일시입니다. 아직 입금되지 않았을 경우 None이 들어갑니다.",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Expand All @@ -161,7 +209,6 @@ def __str__(self):
return f"{self.name}/{self.level}"



class Patron(models.Model):
class Meta:
ordering = ["-total_contribution", "contribution_datetime"]
Expand All @@ -177,7 +224,9 @@ class Meta:
help_text="개인후원을 등록한 유저",
related_name="patron_user",
)
total_contribution = models.IntegerField(default=0, help_text="개인후원한 금액입니다.")
total_contribution = models.IntegerField(
default=0, help_text="개인후원한 금액입니다."
)
contribution_datetime = models.DateTimeField(
help_text="개인후원 결제한 일시입니다."
)
Expand Down
Loading

0 comments on commit 759a5ab

Please sign in to comment.