django-barobill 0.1.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- django_barobill/__init__.py +2 -0
- django_barobill/admin.py +3 -0
- django_barobill/apps.py +6 -0
- django_barobill/choices.py +39 -0
- django_barobill/errors.py +67 -0
- django_barobill/migrations/0001_initial.py +78 -0
- django_barobill/migrations/__init__.py +0 -0
- django_barobill/models.py +387 -0
- django_barobill/parsers.py +29 -0
- django_barobill/tests.py +48 -0
- django_barobill/utils.py +9 -0
- django_barobill/views.py +3 -0
- django_barobill-0.1.0.dist-info/LICENSE +0 -0
- django_barobill-0.1.0.dist-info/METADATA +31 -0
- django_barobill-0.1.0.dist-info/RECORD +17 -0
- django_barobill-0.1.0.dist-info/WHEEL +5 -0
- django_barobill-0.1.0.dist-info/top_level.txt +1 -0
django_barobill/admin.py
ADDED
django_barobill/apps.py
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
from django.db import models
|
2
|
+
|
3
|
+
class BankAccountCollectCycle(models.TextChoices):
|
4
|
+
MINUTE10 = 'MINUTE10', '10분'
|
5
|
+
MINUTE30 = 'MINUTE30', '30분'
|
6
|
+
HOUR1 = 'HOUR1', '1시간'
|
7
|
+
HOUR4 = 'HOUR4', '4시간'
|
8
|
+
DAY1 = 'DAY1', '1일'
|
9
|
+
|
10
|
+
class BankAccountBank(models.TextChoices):
|
11
|
+
KB = 'KB', '국민은행'
|
12
|
+
SHINHAN = 'SHINHAN', '신한은행'
|
13
|
+
NH = 'NH', '농협은행'
|
14
|
+
HANA = 'HANA', '하나은행'
|
15
|
+
SC = 'SC', '제일은행'
|
16
|
+
WOORI = 'WOORI', '우리은행'
|
17
|
+
IBK = 'IBK', '기업은행'
|
18
|
+
KDB = 'KDB', '산업은행'
|
19
|
+
KFCC = 'KFCC', '새마을금고'
|
20
|
+
CITI = 'CITI', '씨티은행'
|
21
|
+
SUHYUP = 'SUHYUP', '수협은행'
|
22
|
+
CU = 'CU', '신협은행'
|
23
|
+
EPOST = 'EPOST', '우체국'
|
24
|
+
KJBANK = 'KJBANK', '광주은행'
|
25
|
+
JBBANK = 'JBBANK', '전북은행'
|
26
|
+
DGB = 'DGB', '대구은행'
|
27
|
+
BUSANBANK = 'BUSANBANK', '부산은행'
|
28
|
+
KNBANK = 'KNBANK', '경남은행'
|
29
|
+
EJEJUBANK = 'EJEJUBANK', '제주은행'
|
30
|
+
KBANK = 'KBANK', '케이뱅크'
|
31
|
+
|
32
|
+
class BankAccountAccountType(models.TextChoices):
|
33
|
+
C = 'C', '법인계좌'
|
34
|
+
P = 'P', '개인계좌'
|
35
|
+
|
36
|
+
class BankAccountTransactionDirection(models.TextChoices):
|
37
|
+
Deposit = 'D', '입금'
|
38
|
+
Withdraw = 'W', '출금'
|
39
|
+
ETC = 'E', '기타'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
error_dict = {
|
2
|
+
# 커스텀
|
3
|
+
901: "해지된 계좌 입니다",
|
4
|
+
902: "해지되지 않은 계좌 입니다",
|
5
|
+
# 기본 오류코드
|
6
|
+
-10000: "알 수 없는 오류 발생. API 호출 중 서버오류가 발생한 경우입니다. 바로빌로 문의바랍니다.",
|
7
|
+
-10003: "연동서비스가 점검 중입니다.",
|
8
|
+
-10004: "해당 기능은 더 이상 사용되지 않습니다.",
|
9
|
+
-10007: "해당 기능을 사용할 수 없습니다.",
|
10
|
+
-10005: "최대 100건까지만 사용하실 수 있습니다.",
|
11
|
+
-10006: "최대 1000건까지만 사용하실 수 있습니다.",
|
12
|
+
-10008: "날짜형식이 잘못되었습니다.",
|
13
|
+
-10148: "조회 기간이 잘못되었습니다.",
|
14
|
+
-40001: "파일을 찾을 수 없습니다.",
|
15
|
+
-40002: "빈 파일입니다(0byte).",
|
16
|
+
# 스크래핑 공통
|
17
|
+
-51001: "서비스가 신청되지 않았습니다.",
|
18
|
+
-51002: "이미 신청되어 있습니다.",
|
19
|
+
-51003: "이미 해지되었습니다.",
|
20
|
+
-51004: "해지 상태가 아닙니다.",
|
21
|
+
-51005: "해지 당월에만 해지 취소할 수 있습니다.",
|
22
|
+
-51006: "해지 당월에는 재신청 할 수 없습니다. 해지 취소로 진행해주세요.",
|
23
|
+
-51007: "테스트베드는 최대 2개까지만 등록할 수 있습니다.",
|
24
|
+
-51008: "이미 수집중입니다.",
|
25
|
+
# 연동정보 관련
|
26
|
+
-10002: "해당 인증키를 찾을 수 없습니다.",
|
27
|
+
-10001: "해당 인증키와 연결된 연계사가 아닙니다.",
|
28
|
+
-24005: "사업자번호와 아이디가 맞지 않습니다.",
|
29
|
+
-50001: "계좌를 찾을 수 없습니다.",
|
30
|
+
-50002: "계좌를 조회할 권한이 없습니다.",
|
31
|
+
-50004: "일일 즉시조회 횟수(10회)를 초과하였습니다.",
|
32
|
+
-50211: "수집주기가 잘못 입력되었습니다.",
|
33
|
+
-50212: "은행 코드가 잘못 입력되었습니다.",
|
34
|
+
-50213: "계좌유형이 잘못 입력되었습니다.",
|
35
|
+
-50214: "계좌번호가 잘못 입력되었습니다.",
|
36
|
+
-50215: "계좌 비밀번호가 잘못 입력되었습니다.",
|
37
|
+
-50216: "계좌 비밀번호를 입력하지 않아야하는 은행입니다.",
|
38
|
+
-50217: "빠른조회 아이디가 잘못 입력되었습니다.",
|
39
|
+
-50218: "빠른조회 아이디를 입력하지 않아야하는 은행입니다.",
|
40
|
+
-50219: "빠른조회 비밀번호가 잘못 입력되었습니다.",
|
41
|
+
-50220: "빠른조회 비밀번호를 입력하지 않아야하는 은행입니다.",
|
42
|
+
-50221: "사업자번호 또는 주민번호(앞6자리)가 잘못 입력되었습니다.",
|
43
|
+
-50222: "사업자번호 또는 주민번호(앞6자리)를 입력하지 않아야하는 은행입니다.",
|
44
|
+
-50223: "유효한 계좌정보가 아닙니다. 계좌정보를 확인해 주시기 바랍니다.",
|
45
|
+
-50224: "계좌정보 검증에 실패하였습니다. 잠시 후 다시 시도해 주시기 바랍니다.",
|
46
|
+
-50225: "이미 등록된 계좌번호입니다.",
|
47
|
+
-50226: "간편조회(빠른조회)서비스에 등록되지 않은 계좌입니다.",
|
48
|
+
-50251: "입출금내역 키(TransRefKey)가 잘못 입력되었습니다.",
|
49
|
+
-50252: "계좌 입출금내역을 찾을 수 없습니다."
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
class BarobillBaseError(Exception):
|
54
|
+
def __init__(self, code, message=None):
|
55
|
+
self.code = int(code)
|
56
|
+
self.message = message or error_dict.get(self.code, f"알 수 없는 오류 코드 : {self.code}")
|
57
|
+
|
58
|
+
def __str__(self):
|
59
|
+
return self.message
|
60
|
+
|
61
|
+
|
62
|
+
class BarobillAPIError(BarobillBaseError):
|
63
|
+
pass
|
64
|
+
|
65
|
+
|
66
|
+
class BarobillError(BarobillBaseError):
|
67
|
+
pass
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2025-01-16 01:16
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
initial = True
|
10
|
+
|
11
|
+
dependencies = [
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.CreateModel(
|
16
|
+
name='Partner',
|
17
|
+
fields=[
|
18
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
19
|
+
('name', models.CharField(max_length=255, unique=True, verbose_name='파트너사명')),
|
20
|
+
('brn', models.CharField(max_length=10, unique=True, verbose_name='사업자등록번호')),
|
21
|
+
('api_key', models.CharField(max_length=36, verbose_name='인증키')),
|
22
|
+
('userid', models.CharField(max_length=256, verbose_name='파트너사 사용자 아이디')),
|
23
|
+
('dev', models.BooleanField(default=False, verbose_name='테스트모드')),
|
24
|
+
],
|
25
|
+
options={
|
26
|
+
'verbose_name': '파트너',
|
27
|
+
'verbose_name_plural': '파트너',
|
28
|
+
},
|
29
|
+
),
|
30
|
+
migrations.CreateModel(
|
31
|
+
name='BankAccount',
|
32
|
+
fields=[
|
33
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
34
|
+
('collect_cycle', models.CharField(choices=[('MINUTE10', '10분'), ('MINUTE30', '30분'), ('HOUR1', '1시간'), ('HOUR4', '4시간'), ('DAY1', '1일')], max_length=10, verbose_name='수집주기')),
|
35
|
+
('bank', models.CharField(choices=[('KB', '국민은행'), ('SHINHAN', '신한은행'), ('NH', '농협은행'), ('HANA', '하나은행'), ('SC', '제일은행'), ('WOORI', '우리은행'), ('IBK', '기업은행'), ('KDB', '산업은행'), ('KFCC', '새마을금고'), ('CITI', '씨티은행'), ('SUHYUP', '수협은행'), ('CU', '신협은행'), ('EPOST', '우체국'), ('KJBANK', '광주은행'), ('JBBANK', '전북은행'), ('DGB', '대구은행'), ('BUSANBANK', '부산은행'), ('KNBANK', '경남은행'), ('EJEJUBANK', '제주은행'), ('KBANK', '케이뱅크')], max_length=10, verbose_name='은행')),
|
36
|
+
('account_type', models.CharField(choices=[('C', '법인계좌'), ('P', '개인계좌')], max_length=1, verbose_name='계좌유형')),
|
37
|
+
('account_no', models.CharField(max_length=50, verbose_name='계좌번호')),
|
38
|
+
('alias', models.CharField(default=None, max_length=50, null=True, verbose_name='별칭')),
|
39
|
+
('usage', models.CharField(default=None, max_length=50, null=True, verbose_name='용도')),
|
40
|
+
('is_stop', models.BooleanField(default=False, verbose_name='해지')),
|
41
|
+
('stop_date', models.DateField(default=None, null=True, verbose_name='해지일')),
|
42
|
+
('partner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='django_barobill.partner', verbose_name='파트너')),
|
43
|
+
],
|
44
|
+
options={
|
45
|
+
'verbose_name': '계좌',
|
46
|
+
'verbose_name_plural': '계좌',
|
47
|
+
},
|
48
|
+
),
|
49
|
+
migrations.CreateModel(
|
50
|
+
name='BankAccountTransaction',
|
51
|
+
fields=[
|
52
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
53
|
+
('trans_direction', models.CharField(choices=[('D', '입금'), ('W', '출금'), ('E', '기타')], max_length=1)),
|
54
|
+
('deposit', models.BigIntegerField(default=None, null=True)),
|
55
|
+
('withdraw', models.BigIntegerField(default=None, null=True)),
|
56
|
+
('balance', models.BigIntegerField(default=0)),
|
57
|
+
('trans_dt', models.DateTimeField()),
|
58
|
+
('trans_type', models.CharField(default=None, max_length=50, null=True, verbose_name='입출금구분')),
|
59
|
+
('trans_office', models.CharField(default=None, max_length=50, null=True, verbose_name='입출금취급점')),
|
60
|
+
('trans_remark', models.CharField(default=None, max_length=50, null=True, verbose_name='입출금비고')),
|
61
|
+
('mgt_remark_1', models.CharField(default=None, max_length=50, null=True, verbose_name='비고1')),
|
62
|
+
('trans_ref_key', models.CharField(max_length=24, verbose_name='입출금내역 키')),
|
63
|
+
('memo', models.CharField(default=None, max_length=100, null=True, verbose_name='입출금내역 키')),
|
64
|
+
('meta', models.JSONField(default=None, null=True, verbose_name='추가 정보')),
|
65
|
+
('bank_account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='django_barobill.bankaccount')),
|
66
|
+
],
|
67
|
+
options={
|
68
|
+
'verbose_name': '입출금 기록',
|
69
|
+
'verbose_name_plural': '입출금 기록',
|
70
|
+
'ordering': ['-trans_dt', 'bank_account'],
|
71
|
+
'unique_together': {('bank_account', 'trans_ref_key')},
|
72
|
+
},
|
73
|
+
),
|
74
|
+
migrations.AddConstraint(
|
75
|
+
model_name='bankaccount',
|
76
|
+
constraint=models.UniqueConstraint(fields=('partner', 'bank', 'account_no'), name='unique_partner_bank_account'),
|
77
|
+
),
|
78
|
+
]
|
File without changes
|
@@ -0,0 +1,387 @@
|
|
1
|
+
import datetime
|
2
|
+
from typing import Optional
|
3
|
+
|
4
|
+
from django.db import models
|
5
|
+
from django.utils import timezone
|
6
|
+
from zeep import Client
|
7
|
+
|
8
|
+
from django_barobill.choices import BankAccountCollectCycle, BankAccountBank, BankAccountAccountType, BankAccountTransactionDirection
|
9
|
+
from django_barobill.errors import BarobillAPIError, BarobillError
|
10
|
+
from django_barobill.parsers import bank_account_log_parser
|
11
|
+
|
12
|
+
|
13
|
+
class BankHelper:
|
14
|
+
def __init__(self, partner):
|
15
|
+
self.partner = partner
|
16
|
+
self.client = self._get_client()
|
17
|
+
|
18
|
+
def _get_client(self):
|
19
|
+
if self.partner.dev:
|
20
|
+
endpoint = "https://testws.baroservice.com/BANKACCOUNT.asmx?wsdl"
|
21
|
+
else:
|
22
|
+
endpoint = "https://ws.baroservice.com/BANKACCOUNT.asmx?wsdl"
|
23
|
+
return Client(endpoint)
|
24
|
+
|
25
|
+
def get_bank_account_management_url(self):
|
26
|
+
return self.client.service.GetBankAccountManagementURL(
|
27
|
+
CERTKEY=self.partner.api_key,
|
28
|
+
CorpNum=self.partner.brn,
|
29
|
+
ID=self.partner.userid,
|
30
|
+
PWD=''
|
31
|
+
)
|
32
|
+
|
33
|
+
def get_bank_account_list(self, avail_only: bool):
|
34
|
+
response = self.client.service.GetBankAccountEx(
|
35
|
+
CERTKEY=self.partner.api_key,
|
36
|
+
CorpNum=self.partner.brn,
|
37
|
+
AvailOnly=1 if avail_only is True else 0,
|
38
|
+
)
|
39
|
+
if response is None:
|
40
|
+
return []
|
41
|
+
return response
|
42
|
+
|
43
|
+
def register_bank_account(
|
44
|
+
self,
|
45
|
+
alias: str,
|
46
|
+
collect_cycle: BankAccountCollectCycle,
|
47
|
+
bank: BankAccountBank,
|
48
|
+
account_type: BankAccountAccountType,
|
49
|
+
account_no: str,
|
50
|
+
password: str,
|
51
|
+
usage: Optional[str] = None,
|
52
|
+
web_id: Optional[str] = None,
|
53
|
+
web_pwd: Optional[str] = None,
|
54
|
+
identity_num: Optional[str] = None
|
55
|
+
):
|
56
|
+
# need test
|
57
|
+
result = self.client.service.RegisterBankAccount(
|
58
|
+
CERTKEY=self.partner.api_key,
|
59
|
+
CorpNum=self.partner.brn,
|
60
|
+
CollectCycle=collect_cycle,
|
61
|
+
Bank=bank,
|
62
|
+
BankAccountType=account_type,
|
63
|
+
BankAccountNum=account_no,
|
64
|
+
BankAccountPwd=password,
|
65
|
+
WebId=web_id,
|
66
|
+
WebPwd=web_pwd,
|
67
|
+
IdentityNum=identity_num,
|
68
|
+
Alias=alias,
|
69
|
+
Usage=usage,
|
70
|
+
)
|
71
|
+
if result != 1:
|
72
|
+
raise BarobillAPIError(result)
|
73
|
+
account, created = BankAccount.objects.update_or_create(
|
74
|
+
partner=self.partner, account_no=account_no, defaults=dict(
|
75
|
+
collect_cycle=collect_cycle, bank=bank, account_type=account_type, alias=alias, usage=usage, is_delete=False
|
76
|
+
)
|
77
|
+
)
|
78
|
+
return account
|
79
|
+
|
80
|
+
def update_bank_accounts(self):
|
81
|
+
account_list = self.get_bank_account_list(avail_only=False)
|
82
|
+
account_no_list = [acc.BankAccountNum for acc in account_list]
|
83
|
+
self.partner.bankaccount_set.filter(
|
84
|
+
account_no__in=account_no_list
|
85
|
+
).update(is_stop=False, stop_date=None, )
|
86
|
+
self.partner.bankaccount_set.exclude(
|
87
|
+
account_no__in=account_no_list
|
88
|
+
).update(is_stop=True, stop_date=timezone.localdate())
|
89
|
+
|
90
|
+
|
91
|
+
class Partner(models.Model):
|
92
|
+
class Meta:
|
93
|
+
verbose_name = '파트너'
|
94
|
+
verbose_name_plural = verbose_name
|
95
|
+
|
96
|
+
name = models.CharField(max_length=255, unique=True, verbose_name='파트너사명')
|
97
|
+
brn = models.CharField(max_length=10, unique=True, verbose_name='사업자등록번호')
|
98
|
+
api_key = models.CharField(max_length=36, verbose_name='인증키')
|
99
|
+
userid = models.CharField(max_length=256, verbose_name='파트너사 사용자 아이디')
|
100
|
+
dev = models.BooleanField(default=False, null=False, verbose_name='테스트모드')
|
101
|
+
|
102
|
+
def __init__(self, *args, **kwargs):
|
103
|
+
super().__init__(*args, **kwargs)
|
104
|
+
self.bank = BankHelper(self)
|
105
|
+
|
106
|
+
|
107
|
+
class BankAccount(models.Model):
|
108
|
+
class Meta:
|
109
|
+
verbose_name = '계좌'
|
110
|
+
verbose_name_plural = verbose_name
|
111
|
+
constraints = [
|
112
|
+
models.UniqueConstraint(fields=['partner', 'bank', 'account_no'], name='unique_partner_bank_account'),
|
113
|
+
]
|
114
|
+
|
115
|
+
partner = models.ForeignKey(Partner, null=False, blank=False, verbose_name='파트너', on_delete=models.PROTECT)
|
116
|
+
collect_cycle = models.CharField(
|
117
|
+
max_length=10, null=False, blank=False, choices=BankAccountCollectCycle.choices, verbose_name='수집주기'
|
118
|
+
)
|
119
|
+
bank = models.CharField(
|
120
|
+
max_length=10, null=False, blank=False, choices=BankAccountBank.choices, verbose_name='은행'
|
121
|
+
)
|
122
|
+
account_type = models.CharField(
|
123
|
+
max_length=1, null=False, blank=False, choices=BankAccountAccountType.choices, verbose_name='계좌유형'
|
124
|
+
)
|
125
|
+
account_no = models.CharField(
|
126
|
+
max_length=50, null=False, blank=False, verbose_name='계좌번호'
|
127
|
+
)
|
128
|
+
alias = models.CharField(max_length=50, null=True, blank=False, default=None, verbose_name='별칭')
|
129
|
+
usage = models.CharField(max_length=50, null=True, blank=False, default=None, verbose_name='용도')
|
130
|
+
is_stop = models.BooleanField(default=False, null=False, verbose_name='해지')
|
131
|
+
stop_date = models.DateField(null=True, blank=False, default=None, verbose_name='해지일')
|
132
|
+
|
133
|
+
def update_bank_account(
|
134
|
+
self,
|
135
|
+
password: Optional[str] = None,
|
136
|
+
web_id: Optional[str] = None,
|
137
|
+
web_pwd: Optional[str] = None,
|
138
|
+
identity_num: Optional[str] = None,
|
139
|
+
alias: Optional[str] = None,
|
140
|
+
usage: Optional[str] = None
|
141
|
+
):
|
142
|
+
request_data = dict(
|
143
|
+
CERTKEY=self.partner.api_key,
|
144
|
+
CorpNum=self.partner.brn,
|
145
|
+
BankAccountNum=self.account_no
|
146
|
+
)
|
147
|
+
if password:
|
148
|
+
request_data['BankAccountPwd'] = password
|
149
|
+
if web_id:
|
150
|
+
request_data['WebId'] = web_id
|
151
|
+
if web_pwd:
|
152
|
+
request_data['WebPwd'] = web_pwd
|
153
|
+
if identity_num:
|
154
|
+
request_data['IdentityNum'] = identity_num
|
155
|
+
if alias:
|
156
|
+
request_data['Alias'] = alias
|
157
|
+
if usage:
|
158
|
+
request_data['Usage'] = usage
|
159
|
+
result = self.partner.bank.client.service.UpdateBankAccount(**request_data)
|
160
|
+
if result != 1:
|
161
|
+
raise BarobillAPIError(result)
|
162
|
+
save_fields = []
|
163
|
+
if self.alias != alias and alias is not None:
|
164
|
+
self.alias = alias
|
165
|
+
save_fields.append('alias')
|
166
|
+
if self.usage != usage and usage is not None:
|
167
|
+
self.usage = usage
|
168
|
+
save_fields.append('usage')
|
169
|
+
if len(save_fields) != 0:
|
170
|
+
self.save(update_fields=save_fields)
|
171
|
+
|
172
|
+
def stop_bank_account(self):
|
173
|
+
if self.is_stop is True:
|
174
|
+
raise BarobillError(901)
|
175
|
+
request_data = dict(
|
176
|
+
CERTKEY=self.partner.api_key,
|
177
|
+
CorpNum=self.partner.brn,
|
178
|
+
BankAccountNum=self.account_no
|
179
|
+
)
|
180
|
+
result = self.partner.bank.client.service.StopBankAccount(**request_data)
|
181
|
+
if result != 1:
|
182
|
+
raise BarobillAPIError(result)
|
183
|
+
self.is_stop = True
|
184
|
+
self.stop_date = timezone.localdate()
|
185
|
+
self.save(update_fields=['is_stop', 'stop_date'])
|
186
|
+
|
187
|
+
def cancel_stop_bank(self):
|
188
|
+
if self.is_stop is False:
|
189
|
+
raise BarobillError(902)
|
190
|
+
request_data = dict(
|
191
|
+
CERTKEY=self.partner.api_key,
|
192
|
+
CorpNum=self.partner.brn,
|
193
|
+
BankAccountNum=self.account_no
|
194
|
+
)
|
195
|
+
result = self.partner.bank.client.service.CancelStopBankAccount(**request_data)
|
196
|
+
if result != 1:
|
197
|
+
raise BarobillAPIError(result)
|
198
|
+
self.is_stop = False
|
199
|
+
self.stop_date = None
|
200
|
+
self.save(update_fields=['is_stop', 'stop_date'])
|
201
|
+
|
202
|
+
def re_register_bank_account(self):
|
203
|
+
if self.is_stop is False:
|
204
|
+
raise BarobillError(902)
|
205
|
+
request_data = dict(
|
206
|
+
CERTKEY=self.partner.api_key,
|
207
|
+
CorpNum=self.partner.brn,
|
208
|
+
BankAccountNum=self.account_no
|
209
|
+
)
|
210
|
+
result = self.partner.bank.client.service.ReRegistBankAccount(**request_data)
|
211
|
+
if result != 1:
|
212
|
+
raise BarobillAPIError(result)
|
213
|
+
self.is_stop = False
|
214
|
+
self.stop_date = None
|
215
|
+
self.save(update_fields=['is_stop', 'stop_date'])
|
216
|
+
|
217
|
+
def __update_log(self, log_list):
|
218
|
+
"""
|
219
|
+
BankAccountLogEx2 의 list 값을 거래 기록에 등록한다.
|
220
|
+
:param log_list: [BankAccountLogEx2]
|
221
|
+
:return:None
|
222
|
+
"""
|
223
|
+
parsed_log_list = map(bank_account_log_parser, log_list)
|
224
|
+
transactions = BankAccountTransaction.objects.bulk_create(
|
225
|
+
[BankAccountTransaction(bank_account=self, **parsed_log) for parsed_log in parsed_log_list],
|
226
|
+
ignore_conflicts=True
|
227
|
+
)
|
228
|
+
|
229
|
+
def update_date_log(self, date_string: str):
|
230
|
+
"""
|
231
|
+
지정한 날짜의 로그를 불러와 데이터베이스에 저장한다.
|
232
|
+
:param date_string: YYYYMMDD 형태의 한국 날짜 string
|
233
|
+
:return: None
|
234
|
+
"""
|
235
|
+
page = 1
|
236
|
+
log_list = []
|
237
|
+
while True:
|
238
|
+
result = self.get_daily_log(date_string, page)
|
239
|
+
log_list += [] if result.BankAccountLogList is None else result.BankAccountLogList.BankAccountLogEx2
|
240
|
+
if result.MaxPageNum == page:
|
241
|
+
break
|
242
|
+
page += 1
|
243
|
+
self.__update_log(log_list)
|
244
|
+
|
245
|
+
def update_today_log(self):
|
246
|
+
"""
|
247
|
+
오늘 거래 내역을 불러오고, 데이터베이스에 저장한다.
|
248
|
+
:return: None
|
249
|
+
"""
|
250
|
+
date_string = timezone.localdate().strftime('%Y%m%d')
|
251
|
+
self.update_date_log(date_string)
|
252
|
+
|
253
|
+
def update_yesterday_log(self):
|
254
|
+
"""
|
255
|
+
어제의 거래 내역을 불러오고, 데이터베이스에 저장한다.
|
256
|
+
:return: None
|
257
|
+
"""
|
258
|
+
date_string = (timezone.localdate() - datetime.timedelta(days=1)).strftime('%Y%m%d')
|
259
|
+
self.update_date_log(date_string)
|
260
|
+
|
261
|
+
def get_log(
|
262
|
+
self,
|
263
|
+
start_date: str,
|
264
|
+
end_date: str,
|
265
|
+
page: int,
|
266
|
+
direction: int = 1,
|
267
|
+
per_page: int = 100,
|
268
|
+
order: int = 1
|
269
|
+
):
|
270
|
+
"""
|
271
|
+
주어진 기간에 대한 거래 내역을 불러온다.
|
272
|
+
https://dev.barobill.co.kr/docs/references/%EA%B3%84%EC%A2%8C%EC%A1%B0%ED%9A%8C-API#GetPeriodBankAccountLogEx2
|
273
|
+
:param start_date: 한국시간 YYYYMMDD 형태의 조회 시작일 string.
|
274
|
+
:param end_date: 한국시간 YYYYMMDD 형태의 조회 종료일 string.
|
275
|
+
:param page: 조회할 페이지 수
|
276
|
+
:param direction: 거래 유형. 1 전체, 2 입금, 3출금
|
277
|
+
:param per_page: 페이지 당 결과 표시 수(최대 100개)
|
278
|
+
:param order: 거래일시 정렬 순서. 1 오름차순, 2. 내림차순
|
279
|
+
:return: barobill API 결과를 그대로 반환한다.(https://dev.barobill.co.kr/docs/references/%EA%B3%84%EC%A2%8C%EC%A1%B0%ED%9A%8C-API#PagedBankAccountLogEx2)
|
280
|
+
"""
|
281
|
+
request_data = dict(
|
282
|
+
CERTKEY=self.partner.api_key,
|
283
|
+
CorpNum=self.partner.brn,
|
284
|
+
ID=self.partner.userid,
|
285
|
+
BankAccountNum=self.account_no,
|
286
|
+
StartDate=start_date,
|
287
|
+
EndDate=end_date,
|
288
|
+
TransDirection=direction,
|
289
|
+
CountPerPage=per_page,
|
290
|
+
CurrentPage=page,
|
291
|
+
OrderDirection=order # 1 오름차순, 2 내림차순
|
292
|
+
)
|
293
|
+
result = self.partner.bank.client.service.GetPeriodBankAccountLogEx2(**request_data)
|
294
|
+
if result.CurrentPage <= 0:
|
295
|
+
raise BarobillAPIError(result.CurrentPage)
|
296
|
+
return result
|
297
|
+
|
298
|
+
def get_daily_log(
|
299
|
+
self,
|
300
|
+
base_date: str,
|
301
|
+
page: int,
|
302
|
+
direction: int = 1,
|
303
|
+
per_page: int = 100,
|
304
|
+
order: int = 1
|
305
|
+
):
|
306
|
+
"""
|
307
|
+
주어진 일자의 거래 내역을 불러온다.
|
308
|
+
https://dev.barobill.co.kr/docs/references/%EA%B3%84%EC%A2%8C%EC%A1%B0%ED%9A%8C-API#GetDailyBankAccountLogEx2
|
309
|
+
:param base_date: 한국시간 YYYYMMDD 형태의 조회일 string.
|
310
|
+
:param page: 조회할 페이지 수
|
311
|
+
:param direction: 거래 유형. 1 전체, 2 입금, 3출금
|
312
|
+
:param per_page: 페이지 당 결과 표시 수(최대 100개)
|
313
|
+
:param order: 거래일시 정렬 순서. 1 오름차순, 2. 내림차순
|
314
|
+
:return: barobill API 결과를 그대로 반환한다.(https://dev.barobill.co.kr/docs/references/%EA%B3%84%EC%A2%8C%EC%A1%B0%ED%9A%8C-API#PagedBankAccountLogEx2)
|
315
|
+
"""
|
316
|
+
request_data = dict(
|
317
|
+
CERTKEY=self.partner.api_key,
|
318
|
+
CorpNum=self.partner.brn,
|
319
|
+
ID=self.partner.userid,
|
320
|
+
BankAccountNum=self.account_no,
|
321
|
+
BaseDate=base_date,
|
322
|
+
TransDirection=direction,
|
323
|
+
CountPerPage=per_page,
|
324
|
+
CurrentPage=page,
|
325
|
+
OrderDirection=order # 1 오름차순, 2 내림차순
|
326
|
+
)
|
327
|
+
result = self.partner.bank.client.service.GetDailyBankAccountLogEx2(**request_data)
|
328
|
+
if result.CurrentPage <= 0:
|
329
|
+
raise BarobillAPIError(result.CurrentPage)
|
330
|
+
return result
|
331
|
+
|
332
|
+
|
333
|
+
def get_monthly_log(
|
334
|
+
self,
|
335
|
+
base_month: str,
|
336
|
+
page: int,
|
337
|
+
direction: int = 1,
|
338
|
+
per_page: int = 100,
|
339
|
+
order: int = 1
|
340
|
+
):
|
341
|
+
"""
|
342
|
+
주어진 일자의 거래 내역을 불러온다.
|
343
|
+
https://dev.barobill.co.kr/docs/references/%EA%B3%84%EC%A2%8C%EC%A1%B0%ED%9A%8C-API#GetMonthlyBankAccountLogEx2
|
344
|
+
:param base_month: 한국시간 YYYYMM 형태의 조회월 string.
|
345
|
+
:param page: 조회할 페이지 수
|
346
|
+
:param direction: 거래 유형. 1 전체, 2 입금, 3출금
|
347
|
+
:param per_page: 페이지 당 결과 표시 수(최대 100개)
|
348
|
+
:param order: 거래일시 정렬 순서. 1 오름차순, 2. 내림차순
|
349
|
+
:return: barobill API 결과를 그대로 반환한다.(https://dev.barobill.co.kr/docs/references/%EA%B3%84%EC%A2%8C%EC%A1%B0%ED%9A%8C-API#PagedBankAccountLogEx2)
|
350
|
+
"""
|
351
|
+
request_data = dict(
|
352
|
+
CERTKEY=self.partner.api_key,
|
353
|
+
CorpNum=self.partner.brn,
|
354
|
+
ID=self.partner.userid,
|
355
|
+
BankAccountNum=self.account_no,
|
356
|
+
BaseMonth=base_month,
|
357
|
+
TransDirection=direction,
|
358
|
+
CountPerPage=per_page,
|
359
|
+
CurrentPage=page,
|
360
|
+
OrderDirection=order # 1 오름차순, 2 내림차순
|
361
|
+
)
|
362
|
+
result = self.partner.bank.client.service.GetDailyBankAccountLogEx2(**request_data)
|
363
|
+
if result.CurrentPage <= 0:
|
364
|
+
raise BarobillAPIError(result.CurrentPage)
|
365
|
+
return result
|
366
|
+
|
367
|
+
|
368
|
+
class BankAccountTransaction(models.Model):
|
369
|
+
class Meta:
|
370
|
+
verbose_name = '입출금 기록'
|
371
|
+
verbose_name_plural = verbose_name
|
372
|
+
unique_together = ('bank_account', 'trans_ref_key')
|
373
|
+
ordering = ['-trans_dt', 'bank_account']
|
374
|
+
|
375
|
+
bank_account = models.ForeignKey(BankAccount, null=False, blank=False, on_delete=models.PROTECT)
|
376
|
+
trans_direction = models.CharField(max_length=1, null=False, blank=False, choices=BankAccountTransactionDirection.choices)
|
377
|
+
deposit = models.BigIntegerField(null=True, blank=False, default=None)
|
378
|
+
withdraw = models.BigIntegerField(null=True, blank=False, default=None)
|
379
|
+
balance = models.BigIntegerField(null=False, blank=False, default=0)
|
380
|
+
trans_dt = models.DateTimeField(null=False, blank=False)
|
381
|
+
trans_type = models.CharField(max_length=50, null=True, blank=False, default=None, verbose_name='입출금구분')
|
382
|
+
trans_office = models.CharField(max_length=50, null=True, blank=False, default=None, verbose_name='입출금취급점')
|
383
|
+
trans_remark = models.CharField(max_length=50, null=True, blank=False, default=None, verbose_name='입출금비고')
|
384
|
+
mgt_remark_1 = models.CharField(max_length=50, null=True, blank=False, default=None, verbose_name='비고1')
|
385
|
+
trans_ref_key = models.CharField(max_length=24, null=False, blank=False, verbose_name='입출금내역 키')
|
386
|
+
memo = models.CharField(max_length=100, null=True, blank=False, default=None, verbose_name='입출금내역 키')
|
387
|
+
meta = models.JSONField(null=True, blank=False, default=None, verbose_name='추가 정보')
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import datetime
|
2
|
+
|
3
|
+
from django_barobill.utils import KST
|
4
|
+
|
5
|
+
|
6
|
+
def bank_account_log_parser(item):
|
7
|
+
"""
|
8
|
+
BankAccountLogEx2를 데이터베이스에 적재할 수 있는 형태로 파싱한다.
|
9
|
+
:param item: BankAccountLogEx2를
|
10
|
+
:return: BankAccountTransaction
|
11
|
+
"""
|
12
|
+
from django_barobill.choices import BankAccountTransactionDirection
|
13
|
+
return dict(
|
14
|
+
trans_direction={
|
15
|
+
"입금": BankAccountTransactionDirection.Deposit,
|
16
|
+
"출금": BankAccountTransactionDirection.Withdraw,
|
17
|
+
"기타": BankAccountTransactionDirection.ETC,
|
18
|
+
}.get(item.TransDirection),
|
19
|
+
deposit=int(item.Deposit),
|
20
|
+
withdraw=int(item.Withdraw),
|
21
|
+
balance=int(item.Balance),
|
22
|
+
trans_dt=KST.localize(datetime.datetime.strptime(item.TransDT, "%Y%m%d%H%M%S")),
|
23
|
+
trans_type=item.TransType,
|
24
|
+
trans_office=item.TransOffice,
|
25
|
+
trans_remark=item.TransRemark,
|
26
|
+
mgt_remark_1=item.MgtRemark1,
|
27
|
+
trans_ref_key=item.TransRefKey,
|
28
|
+
memo=item.Memo,
|
29
|
+
)
|
django_barobill/tests.py
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
import datetime
|
2
|
+
|
3
|
+
from django.test import TestCase
|
4
|
+
from django.utils import timezone
|
5
|
+
|
6
|
+
from django_barobill.choices import BankAccountBank, BankAccountCollectCycle, BankAccountAccountType
|
7
|
+
from django_barobill.models import Partner, BankAccount
|
8
|
+
from django_barobill.parsers import bank_account_log_parser
|
9
|
+
|
10
|
+
|
11
|
+
# Create your tests here.
|
12
|
+
class TestBankAccount(TestCase):
|
13
|
+
def setUp(self):
|
14
|
+
self.partner = Partner.objects.create(
|
15
|
+
name='지구하다ERP',
|
16
|
+
brn='2978601887',
|
17
|
+
api_key='0830C49B-71EA-44E0-81E0-DAAD883B3FC9',
|
18
|
+
userid='cuhong',
|
19
|
+
dev=True
|
20
|
+
)
|
21
|
+
self.bank = BankAccountBank.HANA
|
22
|
+
self.account_no = '26091002164604'
|
23
|
+
self.bank_account = BankAccount.objects.create(
|
24
|
+
partner=self.partner,
|
25
|
+
collect_cycle=BankAccountCollectCycle.MINUTE10,
|
26
|
+
bank=self.bank,
|
27
|
+
account_type=BankAccountAccountType.C,
|
28
|
+
account_no=self.account_no,
|
29
|
+
)
|
30
|
+
|
31
|
+
def test_get_yesterday_log(self):
|
32
|
+
date_string = (timezone.localdate() - datetime.timedelta(days=0)).strftime('%Y%m%d')
|
33
|
+
log_list = []
|
34
|
+
page = 1
|
35
|
+
while True:
|
36
|
+
result = self.bank_account.get_daily_log(date_string, page)
|
37
|
+
log_list += [] if result.BankAccountLogList is None else result.BankAccountLogList.BankAccountLogEx2
|
38
|
+
if result.MaxPageNum == page:
|
39
|
+
break
|
40
|
+
page += 1
|
41
|
+
for log in log_list:
|
42
|
+
print(bank_account_log_parser(log))
|
43
|
+
|
44
|
+
def test_update_today_log(self):
|
45
|
+
self.bank_account.update_today_log()
|
46
|
+
|
47
|
+
ba = BankAccount.objects.first()
|
48
|
+
ba.update_yesterday_log()
|
django_barobill/utils.py
ADDED
django_barobill/views.py
ADDED
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: django-barobill
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A reusable Django app for integration with BaroBill services.
|
5
|
+
Home-page: https://github.com/cuhong/django-barobill
|
6
|
+
Author: cuhong
|
7
|
+
Author-email: hongcoilhouse@gmail.com
|
8
|
+
License: MIT License
|
9
|
+
Classifier: Environment :: Web Environment
|
10
|
+
Classifier: Framework :: Django
|
11
|
+
Classifier: Framework :: Django :: 4.0
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
14
|
+
Classifier: Programming Language :: Python
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
17
|
+
Requires-Python: >=3.8
|
18
|
+
Description-Content-Type: text/markdown
|
19
|
+
License-File: LICENSE
|
20
|
+
Requires-Dist: django>=4.0
|
21
|
+
Requires-Dist: requests==2.32.3
|
22
|
+
Requires-Dist: zeep==4.3.1
|
23
|
+
Dynamic: author
|
24
|
+
Dynamic: author-email
|
25
|
+
Dynamic: classifier
|
26
|
+
Dynamic: description-content-type
|
27
|
+
Dynamic: home-page
|
28
|
+
Dynamic: license
|
29
|
+
Dynamic: requires-dist
|
30
|
+
Dynamic: requires-python
|
31
|
+
Dynamic: summary
|
@@ -0,0 +1,17 @@
|
|
1
|
+
django_barobill/__init__.py,sha256=6APRtokGxem92Eirujfn1lSSABIc2gFsVvfwDIOEf7c,52
|
2
|
+
django_barobill/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
|
3
|
+
django_barobill/apps.py,sha256=VUIGjvRJJKmOM0WaBbqoU5QULCvC0YGKhKIMFYGpXxI,161
|
4
|
+
django_barobill/choices.py,sha256=qkh5baFFCycTOKcTiU2DSu2iDJTiIQyhFgQ8uNSWyDo,1236
|
5
|
+
django_barobill/errors.py,sha256=lKEEEKzAdwAueQOLhoSLe-B9VLT-S7hqUCrkfpkRXp8,3555
|
6
|
+
django_barobill/models.py,sha256=Utls8E_l_dh8Yb8O8HibuaUQara6KakHqQk_RfmZ5K0,16134
|
7
|
+
django_barobill/parsers.py,sha256=boBB9ePTRJrOmoEql23VQk_TDcaWqbEwJhxtW9Gx2Yc,1027
|
8
|
+
django_barobill/tests.py,sha256=iG0hzKegA86ls4QxLY_p6sgZ0fkb_CD0HyzY-aO28ic,1661
|
9
|
+
django_barobill/utils.py,sha256=eKSI-QgM8WTHA1vUukbZnVKEhiMcX7wzxLPcJ_6VKVE,200
|
10
|
+
django_barobill/views.py,sha256=xc1IQHrsij7j33TUbo-_oewy3vs03pw_etpBWaMYJl0,63
|
11
|
+
django_barobill/migrations/0001_initial.py,sha256=Uh8Nx0mOJQjXnPhzXmT7mrQx5zTbE8bNQSJJXTqHNpU,5176
|
12
|
+
django_barobill/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
django_barobill-0.1.0.dist-info/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
+
django_barobill-0.1.0.dist-info/METADATA,sha256=kyC3pz_IHWpZX05M7_5JhfpWEkQmxi5Sg6AyLCnZx7s,996
|
15
|
+
django_barobill-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
16
|
+
django_barobill-0.1.0.dist-info/top_level.txt,sha256=RmcbZUqTKXVI1jksKTaeennFkcSemFHwgxSMPqE7YgU,16
|
17
|
+
django_barobill-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
django_barobill
|