Programming/Project Log

[가계부 만들기] 지출입 기록 - 설계

minarae7 2023. 5. 19. 22:52
728x90
반응형

제일 많이 사용하고 제일 중요한 자료가 되는 것이 바로 지출입 자료일 것이다. 가계부에서 사실 이게 전부라고 할 수 있다.

어쨌든 근본적으로 이 기록을 남기기 위한 기본 설정을 지금까지 해왔다고 할 수 있다.

가계부를 만들기로 한 이유는 바로 형태가 마음에 딱 맞는 것이 없었기 때문이다.

예를 들어서 대형마트에 가서 장을 본다고 했을 때, 이를 세부적으로 분류해서 기록할 수가 없다.

마트에서 장을 보면 장남감을 살 수 있고, 식재료를 살 수 있고, 또는 생활용품을 구매할 수도 있는데 이를 세부적으로 기록할 수 있는 툴을 제공하는 프로그램이 없다.

그래서 일단은 엑셀로 정리해서 사용했는데 아무래도 파일로 기록하다보니 부족함을 느끼게 된다.

그래서 일단 프로그램을 만들어서 사용해보기로 한다.

기록 형태

우선 작성할 때 사용하던 엑셀은 다음 이미지와 같다.

반응형

가계부 스크린샷

사용처는 홈플러스이지만 세부적으로 분류하여서 기록하였다. 이와 같은 형태로 데이터를 주고 받으려면 JSON 형태가 적합할 것으로 보인다.

위의 이미지를 Frontend에서 전달할 때 우선 날짜와 사용처를 담은 객체에 세부 내역을 리스트로 담아서 전달하도록 할 것이다.

테이블 관계는 다음 이미지를 참조하면 된다.

728x90

테이블 관계도

위의 이미지를 Frontend에서 위의 내용을 Json으로 전달한다면 같이 생성해서 전달할 것이다.

반응형
{
  "std_date": "2023-04-15",
  "opponent_name": "홈플러스",
  "items": [
    {
      "detail_contents": "해남고구마2kg",
      "amounts": 10990,
      "io_type": "O",
      "category_no": 23,
      "important": 3,
      "is_fixed_cost": "X"
    },
    {
      "detail_contents": "성주참외_1.2kg",
      "amounts": 8990,
      "io_type": "O",
      "category_no": 25,
      "important": 2,
      "is_fixed_cost": "X"
    },
    {
      "detail_contents": "청양고추_150g",
      "amounts": 1990,
      "io_type": "O",
      "category_no": 23,
      "important": 2,
      "is_fixed_cost": "X"
    }
  ]
}

Schema 생성

그럼 위의 내용을 기준으로 전달받고 결과로 전달할 스키마에 대한 정의를 하도록 한다. 기록과 수정에서 받는 정보는 크게 다르지 않다. 차이가는 index로 사용하는 번호가 있고 없고 차이일 것이다.

그래서 생성과 수정은 같은 스키마를 사용하고 번호를 Optional로 사용하도록 하였다.

반응형
class LogDetailUpsert(BaseModel):
    log_detail_no: Optional[int] = Field(title="사용재역번호")
    detail_contents: str = Field(title="상세내역정보")
    amounts: int = Field(title="금액")
    io_type: Literal["I", "O"] = Field(title="수입/지출 구분(I: 수입, O: 지출)")
    category_no: Optional[int] = Field(title="카테고리 번호")
    important: Optional[int] = Field(title="중요도")
    is_fiexed_cost: Literal["T", "F"] = Field(title="고정비여부(T|F)")

class LogDetail(LogDetailUpsert):
    account_log_no: int = Field(title="내역번호")

    class Config:
        orm_mode = True

class AccountUpsert(BaseModel):
    std_date: date = Field(title="날짜")
    opponent_name: str = Field(title="메인거래처")
    detail_list: List[LogDetailUpsert] = Field(title="세부내역")

class AccountLog(AccountUpsert):
    account_log_no: int = Field(title="내역번호")
    member_no: int = Field(title="사용자번호")

    class Config:
        orm_mode = True

tb_account_log 테이블에서는 account_log_no를 upsert 클래스에 넣지 않았다. 이 값은 생성할 때는 auto_increment로 생성되고 수정할 때는 스키마에 추가되어서 전달되는 대신 URI에 포함되어서 전달받을 것이다.

따라서 Response로 전달할 때만 사용할 것이기 때문에 Upsert에 넣는 대신 AccountLog 클래스에 추가하였다.

이렇게 스키마 정리까지 해서 코드를 작성하기 위한 기본 작업을 마쳤다.

이제 Router와 Service를 추가하여서 로직을 구현하면 된다. 다음 포스팅에서 해당 작업을 진행하도록 하겠다.

728x90
반응형