Skip to content

Commit 35b12d7

Browse files
committed
feat: please pay
1 parent 102acc2 commit 35b12d7

File tree

6 files changed

+399
-7
lines changed

6 files changed

+399
-7
lines changed

docs/docs.html

Lines changed: 26 additions & 6 deletions
Large diffs are not rendered by default.

ent/schema/pleasepay.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package schema
2+
3+
import (
4+
"entgo.io/ent"
5+
"entgo.io/ent/schema/edge"
6+
"entgo.io/ent/schema/field"
7+
"github.com/google/uuid"
8+
)
9+
10+
// PleasePay holds the schema definition for the PayRequest entity.
11+
type PleasePay struct {
12+
ent.Schema
13+
}
14+
15+
// Fields of the PleasePay.
16+
func (PleasePay) Fields() []ent.Field {
17+
return []ent.Field{
18+
field.UUID("id", uuid.UUID{}).Default(uuid.New),
19+
field.Float("amount"),
20+
field.String("state").Default("PENDING"),
21+
}
22+
}
23+
24+
// Edges of the PleasePay.
25+
func (PleasePay) Edges() []ent.Edge {
26+
return []ent.Edge{
27+
edge.To("transaction", Transaction.Type).Unique(),
28+
edge.To("receiver", User.Type).Unique(),
29+
}
30+
}

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,16 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
180180
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
181181
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
182182
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
183+
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
184+
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
183185
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
184186
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
185187
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
186188
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
187189
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
188190
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
191+
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
192+
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
189193
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
190194
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
191195
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -209,6 +213,8 @@ github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
209213
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
210214
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
211215
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
216+
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
217+
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
212218
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
213219
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
214220
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
@@ -446,6 +452,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
446452
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
447453
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
448454
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
455+
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
456+
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
449457
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
450458
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
451459
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

internal/user/user.repository.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func NewRepository(client *ent.Client) UserRepository {
3131
func (r *userRepositoryImpl) FindUserById(ctx context.Context, uid string) (*ent.User, error) {
3232
uuid, err := uuid.Parse(uid)
3333
if err != nil {
34-
return nil, status.Error(codes.FailedPrecondition, "invalid uid")
34+
return nil, status.Error(codes.FailedPrecondition, "invalid uuid")
3535
}
3636

3737
user, err := r.client.User.Query().Where(user.ID(uuid)).First(ctx)

internal/wallet/wallet.grpc.go

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package wallet
22

33
import (
44
"context"
5+
"log"
56
"time"
67

8+
"github.com/google/uuid"
79
"github.com/thinc-org/10-days-paotooong/gen/ent"
10+
"github.com/thinc-org/10-days-paotooong/gen/ent/pleasepay"
811
v1 "github.com/thinc-org/10-days-paotooong/gen/proto/wallet/v1"
912
user_repo "github.com/thinc-org/10-days-paotooong/internal/user"
1013
"google.golang.org/grpc/codes"
@@ -147,3 +150,206 @@ func (s *walletServiceImpl) Topup(ctx context.Context, request *v1.TopupRequest)
147150
},
148151
}, nil
149152
}
153+
154+
func (s *walletServiceImpl) CreatePleasePay(ctx context.Context, request *v1.CreatePleasePayRequest) (*v1.CreatePleasePayResponse, error) {
155+
user, err := s.userRepo.InferUserFromContext(ctx)
156+
if err != nil {
157+
return nil, err
158+
}
159+
160+
pleasePay, err := s.client.PleasePay.Create().SetReceiverID(user.ID).SetAmount(float64(request.GetAmount())).Save(ctx)
161+
if err != nil {
162+
log.Printf("error: %v", err)
163+
return nil, status.Error(codes.Internal, "internal server error")
164+
}
165+
166+
return &v1.CreatePleasePayResponse{
167+
PleasePay: &v1.PleasePay{
168+
Id: pleasePay.ID.String(),
169+
State: mapPleasePayState(pleasePay.State),
170+
ReceiverId: user.ID.String(),
171+
Amount: float32(pleasePay.Amount),
172+
},
173+
}, nil
174+
}
175+
176+
func (s *walletServiceImpl) GetPleasePay(ctx context.Context, request *v1.GetPleasePayRequest) (*v1.GetPleasePayResponse, error) {
177+
userEnt, err := s.userRepo.InferUserFromContext(ctx)
178+
if err != nil {
179+
return nil, err
180+
}
181+
182+
ppId, err := uuid.Parse(request.GetId())
183+
if err != nil {
184+
return nil, status.Error(codes.FailedPrecondition, "invalid uuid")
185+
}
186+
187+
pleasePay, err := s.client.PleasePay.Query().Where(
188+
pleasepay.ID(ppId),
189+
).First(ctx)
190+
if err != nil {
191+
if ent.IsNotFound(err) {
192+
return nil, status.Error(codes.NotFound, "please pay not found")
193+
}
194+
return nil, err
195+
}
196+
197+
receiver, err := pleasePay.QueryReceiver().First(ctx)
198+
if receiver.ID != userEnt.ID {
199+
return nil, status.Error(codes.PermissionDenied, "this is not your please pay")
200+
}
201+
202+
response := &v1.GetPleasePayResponse{
203+
PleasePay: &v1.PleasePay{
204+
Id: pleasePay.ID.String(),
205+
State: mapPleasePayState(pleasePay.State),
206+
ReceiverId: receiver.ID.String(),
207+
Amount: float32(pleasePay.Amount),
208+
},
209+
}
210+
211+
t, err := pleasePay.QueryTransaction().First(ctx)
212+
if err != nil && !ent.IsNotFound(err) {
213+
return nil, err
214+
}
215+
216+
if t != nil {
217+
payer, err := t.QueryPayer().First(ctx)
218+
if err != nil {
219+
log.Printf("cannot find user %v in transaction %v", t.PayerID, t.ID)
220+
return nil, status.Error(codes.Internal, "internal server error")
221+
}
222+
223+
receiver, err := t.QueryReceiver().First(ctx)
224+
if err != nil {
225+
log.Printf("cannot find user %v in transaction %v", t.ReceiverID, t.ID)
226+
return nil, status.Error(codes.Internal, "internal server error")
227+
}
228+
229+
response.PleasePay.Transaction = &v1.Transaction{
230+
TransactionId: t.ID.String(),
231+
Payer: &v1.UserTransaction{
232+
Id: payer.ID.String(),
233+
FirstName: payer.FirstName,
234+
FamilyName: payer.FamilyName,
235+
},
236+
Receiver: &v1.UserTransaction{
237+
Id: receiver.ID.String(),
238+
FirstName: receiver.FirstName,
239+
FamilyName: receiver.FamilyName,
240+
},
241+
Amount: float32(t.Amount),
242+
CreatedAt: &timestamppb.Timestamp{
243+
Seconds: t.CreatedAt.Unix(),
244+
},
245+
Type: v1.TransactionType_TRANSACTION_TYPE_PAY,
246+
}
247+
}
248+
249+
return response, nil
250+
}
251+
252+
func (s *walletServiceImpl) PayPleasePay(ctx context.Context, request *v1.PayPleasePayRequest) (*v1.PayPleasePayResponse, error) {
253+
payer, err := s.userRepo.InferUserFromContext(ctx)
254+
if err != nil {
255+
return nil, err
256+
}
257+
258+
ppId, err := uuid.Parse(request.GetId())
259+
if err != nil {
260+
return nil, status.Error(codes.FailedPrecondition, "invalid uuid")
261+
}
262+
263+
pleasePay, err := s.client.PleasePay.Query().Where(
264+
pleasepay.ID(ppId),
265+
).First(ctx)
266+
if err != nil {
267+
if ent.IsNotFound(err) {
268+
return nil, status.Error(codes.NotFound, "please pay not found")
269+
}
270+
return nil, err
271+
}
272+
273+
if float32(payer.Money) < float32(pleasePay.Amount) {
274+
return nil, status.Error(codes.FailedPrecondition, "not enough money")
275+
}
276+
277+
receiver, err := pleasePay.QueryReceiver().First(ctx)
278+
if err != nil {
279+
return nil, status.Error(codes.NotFound, "receiver not found")
280+
}
281+
282+
amount := pleasePay.Amount
283+
284+
tx, err := s.client.Tx(ctx)
285+
if err != nil {
286+
return nil, status.Error(codes.Internal, "internal server error")
287+
}
288+
289+
_, err = tx.User.UpdateOneID(receiver.ID).SetMoney(receiver.Money + float64(amount)).Save(ctx)
290+
if err != nil {
291+
tx.Rollback()
292+
return nil, status.Error(codes.Internal, "internal server error")
293+
}
294+
295+
_, err = tx.User.UpdateOneID(payer.ID).SetMoney(payer.Money - float64(amount)).Save(ctx)
296+
if err != nil {
297+
tx.Rollback()
298+
return nil, status.Error(codes.Internal, "internal server error")
299+
}
300+
301+
transaction, err := tx.Transaction.Create().SetPayer(payer).SetReceiver(receiver).SetAmount(float64(amount)).SetType("pay").Save(ctx)
302+
if err != nil {
303+
tx.Rollback()
304+
return nil, status.Error(codes.Internal, "internal server error")
305+
}
306+
307+
pleasePayAfter, err := tx.PleasePay.UpdateOneID(pleasePay.ID).SetState("PAID").Save(ctx)
308+
if err != nil {
309+
tx.Rollback()
310+
return nil, status.Error(codes.Internal, "internal server error")
311+
}
312+
313+
err = tx.Commit()
314+
if err != nil {
315+
return nil, status.Error(codes.Internal, "internal server error")
316+
}
317+
318+
return &v1.PayPleasePayResponse{
319+
PleasePay: &v1.PleasePay{
320+
Id: pleasePayAfter.ID.String(),
321+
State: mapPleasePayState(pleasePayAfter.State),
322+
ReceiverId: receiver.ID.String(),
323+
Amount: float32(pleasePay.Amount),
324+
Transaction: &v1.Transaction{
325+
TransactionId: transaction.ID.String(),
326+
Payer: &v1.UserTransaction{
327+
Id: payer.ID.String(),
328+
FirstName: payer.FirstName,
329+
FamilyName: payer.FamilyName,
330+
},
331+
Receiver: &v1.UserTransaction{
332+
Id: receiver.ID.String(),
333+
FirstName: receiver.FirstName,
334+
FamilyName: receiver.FamilyName,
335+
},
336+
Amount: float32(transaction.Amount),
337+
CreatedAt: &timestamppb.Timestamp{
338+
Seconds: transaction.CreatedAt.Unix(),
339+
},
340+
Type: v1.TransactionType_TRANSACTION_TYPE_PAY,
341+
},
342+
},
343+
}, nil
344+
}
345+
346+
func mapPleasePayState(state string) v1.PleasePayState {
347+
switch state {
348+
case "PENDING":
349+
return v1.PleasePayState_PLEASE_PAY_STATE_PENDING
350+
case "PAID":
351+
return v1.PleasePayState_PLEASE_PAY_STATE_PAID
352+
default:
353+
return v1.PleasePayState_PLEASE_PAY_STATE_UNSPECIFIED
354+
}
355+
}

0 commit comments

Comments
 (0)