Line data Source code
1 : // Package profile は、ユーザープロフィールに関するユースケース(アプリケーションロジック)を提供します。
2 : // ドメイン層のエンティティやリポジトリを操作し、アプリケーション全体で再利用可能なビジネスフローを実装します。
3 : package profile
4 :
5 : import (
6 : "context"
7 : "errors"
8 :
9 : "resume/internal/domain/entity"
10 : "resume/internal/shared/apperr"
11 : "resume/internal/shared/valerr"
12 : )
13 :
14 : // CreateUserAddress は 認証済みユーザーの住所を新規登録します
15 : // 入力値に基づきエンティティを生成し、永続化後に CreateUserAddressOutput を返します
16 : // バリデーションエラー(業務ロジックエラー)などが発生した場合は適切なエラーを返します
17 0 : func (uc *Interactor) CreateUserAddress(ctx context.Context, in CreateUserAddressInput) (CreateUserAddressOutput, error) {
18 0 :
19 0 : addr, err := entity.NewUserAddress(entity.UserAddressParam{
20 0 : UserID: in.UserID,
21 0 : PurposeID: in.PurposeID,
22 0 : IsPrimary: in.IsPrimary,
23 0 : CountryCode: in.CountryCode,
24 0 : AdministrativeArea: in.AdministrativeArea,
25 0 : Locality: in.Locality,
26 0 : DependentLocality: in.DependentLocality,
27 0 : PostalCode: in.PostalCode,
28 0 : SortingCode: in.SortingCode,
29 0 : AddressLine1: in.AddressLine1,
30 0 : AddressLine2: in.AddressLine2,
31 0 : AddressLine3: in.AddressLine3,
32 0 : Latitude: in.Latitude,
33 0 : Longitude: in.Longitude,
34 0 : })
35 0 : if err != nil {
36 0 : var inv entity.InvalidAddressError
37 0 : if errors.As(err, &inv) {
38 0 : return CreateUserAddressOutput{}, apperr.New(
39 0 : apperr.CodeUnprocessable,
40 0 : "The request contains semantically invalid data.",
41 0 : valerr.FromDomainAll(inv),
42 0 : )
43 0 : }
44 0 : return CreateUserAddressOutput{}, err
45 : }
46 0 : var saved *entity.UserAddress
47 0 :
48 0 : err = uc.tx.Do(ctx, func(txCtx context.Context) error {
49 0 : // 重複チェック(業務ルール)
50 0 : // 現住所の重複ができない様に確認して重複があればエラーを返す
51 0 : if in.PurposeID == entity.AddressPurposeIDHome {
52 0 : exists, err := uc.uaRepo.ExistsByUserIDAndPurposeID(txCtx, in.UserID, in.PurposeID)
53 0 : if err != nil {
54 0 : return err
55 0 : }
56 0 : if exists {
57 0 : ve := valerr.New()
58 0 : ve.Add(
59 0 : "domain.address.purposeId",
60 0 : "validation.rules.distinct",
61 0 : map[string]any{
62 0 : "field": "domain.address.purposeId.label",
63 0 : },
64 0 : )
65 0 :
66 0 : // 既存のバリデーションエラーと同じ Code/Message/Details で返す
67 0 : return apperr.New(
68 0 : apperr.CodeUnprocessable,
69 0 : "The request contains semantically invalid data.",
70 0 : ve.ToDetails(),
71 0 : )
72 0 : }
73 : }
74 :
75 : // INSERT実行
76 0 : s, err := uc.uaRepo.Create(txCtx, addr)
77 0 : if err != nil {
78 0 : return err
79 0 : }
80 0 : saved = s
81 0 : return nil
82 : })
83 :
84 0 : if err != nil {
85 0 : return CreateUserAddressOutput{}, err
86 0 : }
87 :
88 0 : return CreateUserAddressOutput{
89 0 : saved,
90 0 : }, nil
91 : }
|